diff --git a/.github/actions/build-docker-image/action.yml b/.github/actions/build-docker-image/action.yml deleted file mode 100644 index 4ad9c709d..000000000 --- a/.github/actions/build-docker-image/action.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: build-docker-image -description: build a docker image - -inputs: - context: - description: 'Docker build context' - required: true - tag: - description: 'Docker image name' - required: true - -runs: - using: "composite" - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Build Docker Image - shell: bash - run: | - docker build ${{ inputs.context }} --file ${{ inputs.context }}/Dockerfile --tag ${{ inputs.tag }}:$GITHUB_SHA - docker save ${{ inputs.tag }}:$GITHUB_SHA | gzip > ${{ inputs.tag }}-image.tar.gz - - - name: Upload artifact - uses: actions/upload-artifact@v2 - with: - name: ${{ inputs.tag }}-image - path: ./${{ inputs.tag }}-image.tar.gz - retention-days: 1 \ No newline at end of file diff --git a/.github/actions/release-docker-image/action.yml b/.github/actions/release-docker-image/action.yml deleted file mode 100644 index ba94cd959..000000000 --- a/.github/actions/release-docker-image/action.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: release-docker-image -description: release a docker image to the github registry - -inputs: - username: - description: 'GitHub username' - required: true - password: - description: 'GitHub password' - required: true - image: - description: 'Docker image' - required: true - -runs: - using: "composite" - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Login to GitHub Container Registry - shell: bash - run: echo "${{ inputs.password }}" | docker login https://ghcr.io -u ${{ inputs.username }} --password-stdin - - - name: Download artifact - uses: actions/download-artifact@v2 - with: - name: ${{ inputs.image }}-image - - - name: Push to GitHub Container Registry - shell: bash - run: | - IMAGE_ID=ghcr.io/learnlib/alex/${{ inputs.image }} - BRANCH=${GITHUB_REF#"refs/heads/"} - VERSION=unstable - - docker load < ${{ inputs.image }}-image.tar.gz - docker tag ${{ inputs.image }}:$GITHUB_SHA $IMAGE_ID:$VERSION - docker push $IMAGE_ID:$VERSION - docker tag ${{ inputs.image }}:$GITHUB_SHA $IMAGE_ID:$GITHUB_SHA - docker push $IMAGE_ID:$GITHUB_SHA diff --git a/.github/settings.xml b/.github/settings.xml deleted file mode 100644 index 605000ef2..000000000 --- a/.github/settings.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - false - - - - ossrh - ${env.OSSRH_TOKEN_USERNAME} - ${env.OSSRH_TOKEN_PASSWORD} - - - diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 10b7befa4..000000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,286 +0,0 @@ -name: CI - -on: - push: - branches: - - main - pull_request: - branches: - - main - -permissions: - contents: write - -jobs: - build-backend: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Set up JDK 17 - uses: actions/setup-java@v1 - with: - java-version: 17 - - name: Cache local Maven repository - uses: actions/cache@v2 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-build-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven-build- - - name: Build with Maven - run: mvn clean install -DskipTests package --file ./backend/pom.xml - - lint-backend: - needs: build-backend - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 - with: - java-version: 17 - - name: Cache local Maven repository - uses: actions/cache@v2 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-lint-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven-lint- - - name: Lint Java Code - run: mvn checkstyle:checkstyle -Pcode-analysis --file ./backend/pom.xml - - analyse-backend: - needs: build-backend - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 - with: - java-version: 17 - - name: Cache local Maven repository - uses: actions/cache@v2 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-analyse-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven-analyse- - - name: Analyse Java Code for bugs - run: mvn install -DskipTests --file ./backend/pom.xml && mvn spotbugs:check -Pcode-analysis --file ./backend/pom.xml - - test-unit-backend: - needs: [lint-backend, analyse-backend] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Set up JDK 17 - uses: actions/setup-java@v1 - with: - java-version: 17 - - name: Cache local Maven repository - uses: actions/cache@v2 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-test-unit-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven-test-unit- - - name: Run unit tests with Maven - run: mvn clean test --file ./backend/pom.xml - - test-integration-backend: - needs: test-unit-backend - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Set up JDK 17 - uses: actions/setup-java@v1 - with: - java-version: 17 - - name: Cache local Maven repository - uses: actions/cache@v2 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-test-integration-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven-test-integration- - - name: Run integration tests with Maven - run: mvn clean verify -Dsurefire.skip=true --file ./backend/pom.xml - - package-backend: - needs: test-integration-backend - runs-on: ubuntu-latest - if: github.event_name == 'push' - steps: - - uses: actions/checkout@v2 - - name: Build the Docker image for the backend - uses: ./.github/actions/build-docker-image - with: - context: ./backend - tag: alex-backend - - lint-frontend: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Lint TypeScript code - uses: actions/setup-node@v2 - with: - node-version: '16' - - run: cd ./frontend && npm ci && npm run lint - - test-unit-frontend: - needs: lint-frontend - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Run Angular unit tests - uses: actions/setup-node@v2 - with: - node-version: '16' - - run: cd ./frontend && npm ci && npm run test -- --no-watch --no-progress --browsers=ChromeHeadlessCI - - package-frontend: - needs: test-unit-frontend - runs-on: ubuntu-latest - if: github.event_name == 'push' - steps: - - uses: actions/checkout@v2 - - name: Build the Docker image for the frontend - uses: ./.github/actions/build-docker-image - with: - context: ./frontend - tag: alex-frontend - - lint-cli: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Lint CI TypeScript code - uses: actions/setup-node@v2 - with: - node-version: '16' - - run: cd ./cli && npm ci && npm run lint - - package-cli: - needs: lint-cli - runs-on: ubuntu-latest - if: github.event_name == 'push' - steps: - - uses: actions/checkout@v2 - - name: Build the Docker image for the CLI - uses: ./.github/actions/build-docker-image - with: - context: ./cli - tag: alex-cli - - build-docs: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Build docs - uses: actions/setup-node@v2 - with: - node-version: '16' - - run: cd ./docs && npm install -g npm && npm ci && npm run build - - name: Upload docs - uses: actions/upload-artifact@v3 - with: - name: docs - path: ./docs/.vuepress/dist/ - - package-docs: - needs: build-docs - runs-on: ubuntu-latest - if: github.event_name == 'push' - steps: - - uses: actions/checkout@v2 - - name: Build the Docker image for the docs - uses: ./.github/actions/build-docker-image - with: - context: ./docs - tag: alex-docs - - release-images: - needs: - - package-frontend - - package-backend - - package-cli - - package-docs - runs-on: ubuntu-latest - if: github.event_name == 'push' - steps: - - uses: actions/checkout@v2 - - name: Release frontend - uses: ./.github/actions/release-docker-image - with: - username: ${{ github.actor }} - password: ${{ secrets.CR_PAT }} - image: alex-frontend - - name: Release backend - uses: ./.github/actions/release-docker-image - with: - username: ${{ github.actor }} - password: ${{ secrets.CR_PAT }} - image: alex-backend - - name: Release CLI - uses: ./.github/actions/release-docker-image - with: - username: ${{ github.actor }} - password: ${{ secrets.CR_PAT }} - image: alex-cli - - name: Release docs - uses: ./.github/actions/release-docker-image - with: - username: ${{ github.actor }} - password: ${{ secrets.CR_PAT }} - image: alex-docs - - release-packages: - needs: - - package-frontend - - package-backend - - package-cli - - package-docs - runs-on: ubuntu-latest - if: github.event_name == 'push' - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Set up JDK 17 - uses: actions/setup-java@v1 - with: - java-version: 17 - - name: Set up cache - uses: actions/cache@v2 - with: - path: | - ~/.m2 - !~/.m2/repository/de/learnlib/alex - key: cache-deploy-${{ hashFiles('backend/**/pom.xml') }} - restore-keys: cache-deploy- - - name: Run Maven - env: # make secrets available as environment variables - OSSRH_TOKEN_USERNAME: ${{ secrets.OSSRH_TOKEN_USERNAME }} - OSSRH_TOKEN_PASSWORD: ${{ secrets.OSSRH_TOKEN_PASSWORD }} - run: cd backend && mvn -B -s $GITHUB_WORKSPACE/.github/settings.xml install deploy -DskipTests - - pages: - needs: - - package-frontend - - package-backend - - package-cli - - package-docs - runs-on: ubuntu-latest - if: github.event_name == 'push' - steps: - - name: Checkout repo - uses: actions/checkout@v3 - - name: Create book directory - run: cd website && mkdir book - - name: Download docs - uses: actions/download-artifact@v3 - with: - name: docs - path: ./website/book - - name: Publish pages - uses: JamesIves/github-pages-deploy-action@v4 - with: - folder: website \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 1385cf2f9..000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Release - -on: - workflow_dispatch: - inputs: - version: - description: 'The version of the release' - required: true - -jobs: - release-cli-to-npm: - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Setup NodeJS - uses: actions/setup-node@v1 - with: - node-version: 16 - registry-url: https://registry.npmjs.org/ - - - name: Publish CLI - run: cd cli && npm ci && npm publish - env: - NODE_AUTH_TOKEN: ${{secrets.npm_token}} - - tag-docker-images: - runs-on: ubuntu-latest - steps: - - name: Login to GitHub Container Registry - run: echo "${{ secrets.CR_PAT }}" | docker login https://ghcr.io -u ${{ github.actor }} --password-stdin - - - name: Tag latest images with release version - run: | - VERSION="@@@${{github.event.inputs.version}}@@@" - IMAGES="alex-frontend alex-backend alex-cli alex-docs" - - for img in $IMAGES - do - echo "ghcr.io/learnlib/alex/$img:$VERSION" - docker pull "ghcr.io/learnlib/alex/$img:unstable" - docker tag "ghcr.io/learnlib/alex/$img:unstable" "ghcr.io/learnlib/alex/$img:$VERSION" - docker tag "ghcr.io/learnlib/alex/$img:unstable" "ghcr.io/learnlib/alex/$img:latest" - docker push "ghcr.io/learnlib/alex/$img:$VERSION" - docker push "ghcr.io/learnlib/alex/$img:latest" - done diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 651b64255..000000000 --- a/.gitignore +++ /dev/null @@ -1,29 +0,0 @@ -# IntelliJ -.idea -*.iml - -# Java -main/logs -target -*.class -hs_err_pid* - -# log files -backend/logs -backend/debug.log - -# JavaScript -cli/src/main/javascript/node_modules -frontend/src/main/javascript/node_modules -frontend/src/main/javascript/dist -frontend/src/main/javascript/test/coverage -frontend/src/main/javascript/npm-debug\.log - -# helm value files -infrastructure/helm-chart/values-temp.yml -infrastructure/helm-chart/values-temp.yaml -infrastructure/helm-chart/secrets.yml -infrastructure/helm-chart/secrets.yaml - -# uploaded files -main/uploads diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/.nojekyll @@ -0,0 +1 @@ + diff --git a/.resources/code-style-intellij.xml b/.resources/code-style-intellij.xml deleted file mode 100644 index 11085a77f..000000000 --- a/.resources/code-style-intellij.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/.resources/images/favicon.png b/.resources/images/favicon.png deleted file mode 100644 index 729b9472c..000000000 Binary files a/.resources/images/favicon.png and /dev/null differ diff --git a/.resources/images/favicon.psd b/.resources/images/favicon.psd deleted file mode 100644 index 60512bd27..000000000 Binary files a/.resources/images/favicon.psd and /dev/null differ diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index ef9329b37..000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,328 +0,0 @@ -# Changelog - -## ALEX 3.0.0 - -### Breaking Changes - -* Due to the removal of the unique name constraint for symbols, project files created with previous releases are not compatible with this release. -* Due to the CLI overhaul, the CLI got a new API with is not compatible with previous releases. - -### Fixes - -* Fix issue with JSON path evaluation that returns a JSON object -* Fix issue with local usage of ALEX with the Chrome image - -### Features - -* Make ALEX Kubernetes ready: - * Added Helm chart to `infratructure/helm`. - * Added Skaffold pipeline for local Kubernetes development. -* Symbol names must not be unique in the project. - Instead, symbol names must be unique within a symbol group. -* CLI overhaul: new API. -* Allow Webhooks to have custom HTTP headers. -* Add validation widget for learner setups. -* Allow to send PATCH requests via an action. - -### Changes - -* Symbols and tests cannot be exported and imported separately anymore. -* Update to Selenium 4 -* Remove support for Internet Explorer and HTML Unit - -## ALEX 2.1.1 - -### Fixes - -* Fix bug where test cases could not be executed. -* Fix bug where tests could not be saved when pre steps have changed. - -## ALEX 2.1.0 - -### Breaking Changes - -* Use Docker for development and production versions of ALEX. - The standalone build is no longer supported. -* Due to the previous point, the web drivers have been removed. - It is only possible to set the URL to a Selenium Hub. - -### Features - -* See which symbols and tests are used by other users in a project -* Export formula suites while exporting a project -* Export learner setups while exporting a project -* Automated model checking of learned models - * Associate LTL formula suites with a learner setup - -## ALEX 2.0.0 - -### Fixes - -* Scoping issues with variables - -### Improvements - -* Add Flyway support -* Migrate frontend to Angular 8 -* Server-side import and export -* Add stack trace for failed tests -* Abort test processes more quickly -* Show symbol references -* Support for Java 11 - -### Features - -* Project environments: create environments and environment variables -* New actions: - * Drag and drop operations - * goto-like jumps - * waiting for a script -* Update a test suite during test generation -* Extend "switch to" action for handling windows -* Import and export for projects -* Specify default test configurations -* Multiple pre and post steps for test cases -* Queue test and learning processes -* Save learning setups -* Collaboration for projects - -## ALEX 1.7.2 - -### Fixes - -* Generate test case from model -* Add cookie to request action - -## ALEX 1.7.1 - -### Fixes - -* Fix model not displayed in testing view - -## ALEX 1.7.0 - -### Breaking Changes - -* Removed the HTML Element Picker. - The picker only really worked in Chrome and then only in some selected use cases, i.e. static pages. - Due to these restrictions we decided to remove it completely. -* Removed xvfb option. - The option was introduced when major browsers did not have a headless mode. - Since the option only worked on Linux systems and all major browsers have such a mode, the option has been removed. - -### Features - -* Basic LTL-based model checking using [LTSmin](https://ltsmin.utwente.nl/). -* Compatibility with Java > 8. -* Add action to set a variable by HTTP status. -* Improved parallelisation support for learning processes. -* Permanently delete symbols instead of just hiding them. - This only works if a symbol is not referenced by some other entity. -* Symbol groups can have the same name when they don't share the parent group. -* New events for when symbols are deleted permanently. -* New model checker related events. -* The JWT expires after 7 days. - -### Fixes - -* Test results are ordered properly. -* Fix resuming learning processes with new input symbols. - - -## ALEX 1.6.1 - -### Fixes - -* Fix issues with HTML Element Picker - - -## ALEX 1.6.0 - -### Breaking Changes - -* Symbols have to be migrated to the new version. - Please use the migration script `src/main/resources/migration/1.6.0/migrate-symbols-1.5.0-to-1.6.0.js` via: - - `node migrate-symbols-1.5.0-to-1.6.0.js ./symbols-from-1.5.0.json ./symbols-for-1.6.0.json` - -* Tests have to be migrated to the new version. - Please use the migration script `src/main/resources/migration/1.6.0/migrate-tests-1.5.0-to-1.6.0.js` via: - - `node migrate-tests-1.5.0-to-1.6.0.js ./tests-from-1.5.0.json ./tests-for-1.6.0.json` - -### Features - -* Symbols can be composed of other symbols. -* Symbols can be parameterized in learning experiments. -* Connect ALEX to a MySQL database. - See the README for instructions. -* Generate test suites from discrimination tree based learners (TTT, Discrimination Tree). -* Use test cases in test suites as equivalence oracle. -* Added support for Internet Explorer -* Execute JavaScript asynchronously -* Symbol parameters can be *public* or *private*. - If a parameter is public, its value can be set by the user while configuring a testing or learning process. - If it is private, its value cannot be set manually, but is resolved by the value in the global data context. - - -## ALEX 1.5.1 - -This release only contains some bug fixes. - - -## ALEX 1.5.0 - -### Breaking Changes - -* Symbols and tests that have been exported with v.1.4.0 and lower can not be imported directly. - Apply the new export format and for each symbol in an exported JSON file add the properties `inputs` and `outputs` so that the resulting file looks like: - - ```JSON - { - "version": "1.4.0", - "type": "symbols", - "symbols": [ - { - "name": "symbol", - ..., - "inputs": [], - "outputs": [] - }, - ... - ] - } - ``` - -### Bug Fixes - -* Resuming a learning process should now work as expected. -* Various smaller fixes. - -### Features - -* The results of test executions are saved in reports. -* Added webhooks to notify external applications about changes. -* Reuse the browser instance for membership queries. - A hard reset with a new browser instance can be achieved with a new action. -* New actions: - * Refresh and restart the browser window. - * Click on a arbitrary element with a given visible text. - * Check if an element, e.g. a checkbox, radio button or option is selected. - * Set variable to HTTP response body. -* Parameterized symbols: symbols now have dynamic inputs and outputs. - Values for inputs can be set by a user for modelling tests. -* Symbols and symbol groups can be nested in a tree like structure. -* Named project URLs. -* Download uploaded files. -* Learner results can be cloned. -* Import and export symbol groups. - -### Further Comments - -* The CLI for ALEX is now a standalone NPM package and can be installed via `npm install alex-cli` - - -## ALEX 1.4.0 - -### Breaking Changes - -* Symbol abbreviations have been removed. To use old exported symbol sets, remove the *abbreviation* property manually -from the JSON file. - -* The HTML Element Picker does not work as before. In order to use it properly, make sure you start your browser with -disabled CORS rules or use a plugin. See the [user documentation](http://learnlib.github.io/alex/book/1.4.0/) for -detailed instructions. - -### Features - -* Define a default web driver to execute tests in -* Immediately stop learning instead of waiting for the current iteration to finish -* Support for native headless web driver support for Chrome and Firefox -* Action recorder - Record a sequence of actions for a symbol in the Element Picker -* Extended testing capability - Save and execute test cases without starting a learning process -* Calculate the difference between two models -* Added Safari driver -* New actions: - * Wait for a text to appear - * Wait for the value of an elements attribute - * Interact with alert, prompt and confirm dialogs - * Validate JSON against a JSON schema - -See the [user documentation](http://learnlib.github.io/alex/book/1.4.0/) for more details. - -## ALEX 1.3.0 - -### Breaking Changes - -* The execute symbol action is no longer supported - -### Features - -* Possibility to resume old learning experiments - -## ALEX v1.2.1 - -### Breaking Changes - -* Actions that deal with web elements have to be updated: - - ``` - node: {selector: '...', type: 'CSS|XPATH'} - ``` - -### Features - -* New actions: - * Set a variable by node count - * Set a variable by regex -* Switch between XPath and CSS selectors in actions -* Experimental parallel test execution support - -## ALEX v1.2 - -### Features - -* New actions: - * Press special keys like enter, ctrl, etc. - * Check the value of an elements attribute -* New equivalence oracle: hypothesis -* Test symbols without starting a learning process -* Support for the edge driver - -## ALEX v1.1.2 - -### Breaking Changes - -* Dropped support for IE web driver -* Firefox and Chrome drivers are not supported by default any longer. - Instead, you have specify the paths to the driver executables. - -### Bug Fixes - -* Fixed the parsing of JSON paths in various REST actions. - -### Features - -* New action: Move mouse -* Click action supports double click - -## ALEX v1.1 (and hidden ALEX v1.1.1) - -### Bug Fixes - -* Allow symbol groups to be edited via the frontend again -* Properly close connectors after finished learning -* ALEX v1.1.1 fixed a problem with the fonts. - -### Features - -* New action: Execute JavaScript -* GoTo action and Call action support Basic HTTP authentication -* Export and import projects -* New REST endpoint: rest/users/batch/{ids} to delete multiple users at once -* Additional visual enhancements - -### Other - -* Updated frontend and backend dependencies -* Removed requirement to have grunt and grunt-cli installed globally diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index c0f365ff7..000000000 --- a/LICENSE.txt +++ /dev/null @@ -1,191 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -Copyright 2015 - 2020 TU Dortmund - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/README.md b/README.md deleted file mode 100644 index 6d4069178..000000000 --- a/README.md +++ /dev/null @@ -1,29 +0,0 @@ -![main branch ci](https://github.com/learnlib/alex/actions/workflows/ci.yml/badge.svg?branch=main) -![version](https://img.shields.io/badge/version-v3.0.0-blue) - -

- -

- -# ALEX - -Automata Learning EXperience (ALEX) is a Web application that allows you run automated tests on web -applications and JSON-based APIs using active automata learning. - -Users model [Selenium][selenium]- or HTTP-based test inputs for their application, which are used to automatically infer -an automaton model (a [Mealy machine][mealy]), which represents the behavior of the web application. - -## Documentation - -* [User manual](https://learnlib.github.io/alex/book/) -* [Installation](https://learnlib.github.io/alex/book/contents/getting-started/installation/) -* [Examples](https://learnlib.github.io/alex/book/contents/examples/todomvc/) -* [Developer docs](https://learnlib.github.io/alex/book/contents/dev-docs/development/) - -## Background - -* [Active automata learning](https://scholar.google.de/scholar?hl=de&q=active+automata+learning) -* [ALEX: Mixed-Mode Learning of Web Applications at Ease](https://link.springer.com/chapter/10.1007/978-3-319-47169-3_51) - -[mealy]: https://en.wikipedia.org/wiki/Mealy_machine -[selenium]: https://www.seleniumhq.org/ diff --git a/website/assets/favicons/android-chrome-192x192.png b/assets/favicons/android-chrome-192x192.png similarity index 100% rename from website/assets/favicons/android-chrome-192x192.png rename to assets/favicons/android-chrome-192x192.png diff --git a/website/assets/favicons/android-chrome-512x512.png b/assets/favicons/android-chrome-512x512.png similarity index 100% rename from website/assets/favicons/android-chrome-512x512.png rename to assets/favicons/android-chrome-512x512.png diff --git a/website/assets/favicons/apple-touch-icon.png b/assets/favicons/apple-touch-icon.png similarity index 100% rename from website/assets/favicons/apple-touch-icon.png rename to assets/favicons/apple-touch-icon.png diff --git a/website/assets/favicons/browserconfig.xml b/assets/favicons/browserconfig.xml similarity index 100% rename from website/assets/favicons/browserconfig.xml rename to assets/favicons/browserconfig.xml diff --git a/website/assets/favicons/favicon-16x16.png b/assets/favicons/favicon-16x16.png similarity index 100% rename from website/assets/favicons/favicon-16x16.png rename to assets/favicons/favicon-16x16.png diff --git a/website/assets/favicons/favicon-32x32.png b/assets/favicons/favicon-32x32.png similarity index 100% rename from website/assets/favicons/favicon-32x32.png rename to assets/favicons/favicon-32x32.png diff --git a/website/assets/favicons/favicon.ico b/assets/favicons/favicon.ico similarity index 100% rename from website/assets/favicons/favicon.ico rename to assets/favicons/favicon.ico diff --git a/website/assets/favicons/mstile-150x150.png b/assets/favicons/mstile-150x150.png similarity index 100% rename from website/assets/favicons/mstile-150x150.png rename to assets/favicons/mstile-150x150.png diff --git a/website/assets/favicons/safari-pinned-tab.svg b/assets/favicons/safari-pinned-tab.svg similarity index 100% rename from website/assets/favicons/safari-pinned-tab.svg rename to assets/favicons/safari-pinned-tab.svg diff --git a/website/assets/favicons/site.webmanifest b/assets/favicons/site.webmanifest similarity index 100% rename from website/assets/favicons/site.webmanifest rename to assets/favicons/site.webmanifest diff --git a/website/assets/images/background.jpg b/assets/images/background.jpg similarity index 100% rename from website/assets/images/background.jpg rename to assets/images/background.jpg diff --git a/website/assets/images/features-1.png b/assets/images/features-1.png similarity index 100% rename from website/assets/images/features-1.png rename to assets/images/features-1.png diff --git a/website/assets/images/features-2.png b/assets/images/features-2.png similarity index 100% rename from website/assets/images/features-2.png rename to assets/images/features-2.png diff --git a/website/assets/images/features-3.png b/assets/images/features-3.png similarity index 100% rename from website/assets/images/features-3.png rename to assets/images/features-3.png diff --git a/docs/assets/logo.png b/assets/images/logo.png similarity index 100% rename from docs/assets/logo.png rename to assets/images/logo.png diff --git a/website/assets/js/bootstrap.bundle.min.js b/assets/js/bootstrap.bundle.min.js similarity index 100% rename from website/assets/js/bootstrap.bundle.min.js rename to assets/js/bootstrap.bundle.min.js diff --git a/website/assets/styles/bootstrap.min.css b/assets/styles/bootstrap.min.css similarity index 100% rename from website/assets/styles/bootstrap.min.css rename to assets/styles/bootstrap.min.css diff --git a/website/assets/styles/style.css b/assets/styles/style.css similarity index 100% rename from website/assets/styles/style.css rename to assets/styles/style.css diff --git a/backend/Dockerfile b/backend/Dockerfile deleted file mode 100644 index 6eee7018c..000000000 --- a/backend/Dockerfile +++ /dev/null @@ -1,31 +0,0 @@ -FROM docker.io/library/maven:3.8-openjdk-17-slim as builder-backend -RUN mkdir -p /backend -WORKDIR /backend -COPY ./pom.xml /backend/pom.xml -RUN mvn verify -DskipTests -COPY . /backend -RUN mvn install package -DskipTests - -FROM docker.io/library/debian:buster-slim as builder-ltsmin -RUN mkdir -p /ltsmin -WORKDIR /ltsmin -RUN apt-get update -qq && apt-get upgrade -qq && apt-get install -qq wget -RUN wget https://github.com/utwente-fmt/ltsmin/releases/download/v3.0.2/ltsmin-v3.0.2-linux.tgz -RUN tar -xzf ltsmin-v3.0.2-linux.tgz -RUN mv v3.0.2 ltsmin - -FROM docker.io/library/openjdk:17-slim -COPY --from=builder-backend /backend/target/ALEX-3.0.0-exec.jar /usr/share/java/alex/alex.jar -COPY --from=builder-ltsmin /ltsmin/ltsmin /opt/ltsmin -WORKDIR /var/lib/alex - -EXPOSE 8000 - -CMD java -jar /usr/share/java/alex/alex.jar \ - --ltsmin.path=/opt/ltsmin/bin \ - --spring.datasource.url="jdbc:postgresql://${DATABASE_HOST}:${DATABASE_PORT}/${DATABASE_NAME}" \ - --spring.datasource.username="${DATABASE_USER}" \ - --spring.datasource.password="${DATABASE_PASSWORD}" \ - --selenium.grid.host="${GRID_HOST}" \ - --selenium.grid.port="${GRID_PORT}" \ - --runtime="${RUNTIME}" diff --git a/backend/pom.xml b/backend/pom.xml deleted file mode 100644 index 91adb9fe7..000000000 --- a/backend/pom.xml +++ /dev/null @@ -1,646 +0,0 @@ - - - - - 4.0.0 - - - 3.2.1 - - - - - central - Maven Repository Switchboard - default - https://repo.maven.apache.org/maven2/ - - false - - - - - sonatype-nexus-snapshots - Sonatype Nexus Snapshots - https://oss.sonatype.org/content/repositories/snapshots - - false - - - true - - - - - - https://github.com/LearnLib/alex.git - HEAD - - - - GitHub - https://github.com/LearnLib/alex/issues - - - GitHub Actions - https://github.com/LearnLib/alex/actions - - - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - false - - - - alex-backend - jar - - Automata Learning Experience (ALEX) - 3.0.0 - de.learnlib.alex - - - A web application for interring Mealy machines of Web applications via active automata learning. - - - - - de.learnlib.alex.AlexApp - UTF-8 - UTF-8 - 17 - 17 - - - 3.8.0 - 3.1.1 - 3.0.0-M5 - 3.0.0-M5 - 3.2.2 - 2.7 - 4.3.0 - 3.1.0 - 2.10.4 - 3.0.0-M5 - 3.0.0-M5 - 0.8.2 - 3.1.2 - 8.41 - 4.5.3.0 - 4.5.3 - - - 2.7.9 - 0.15.0 - 0.10.0 - 4.8.1 - 0.7.0 - 1.11.0 - 1.4.01 - 1.15.3 - 2.6.0 - 42.6.0 - 2.14.2 - 5.7.0 - 2.23.0 - 2.35 - 2.2.10 - 2.4.0-b180830.0359 - 8.4.3 - 3.0.3 - 1.16.3 - 2.14.0 - 4.0.3 - 2.8.0 - 1.10.0 - - false - - - - - Apache License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0 - manual - - - - - - Alexander Bainczyk - alexander.bainczyk@tu-dortmund.de - - - Marco Krumrey - marco.krumrey@tu-dortmund.de - - - - - Oliver Bauer - oliver.bauer@tu-dortmund.de - - - Dr. Johannes Neubauer - johannes.neubauer@tu-dortmund.de - - - Malte Isberner - malte.isberner@tu-dortmund.de - - - Prof. Dr. Bernhard Steffen - bernhard.steffen@tu-dortmund.de - - - Philipp Koch - philipp.koch@tu-dortmund.de - - - Alexander Schieweck - alexander.schieweck@tu-dortmund.de - - - - Chair for Programming Systems at TU Dortmund University, Germany - http://ls5-www.cs.tu-dortmund.de/ - - - - - - - com.google.guava - guava - 31.1-jre - - - - - org.springframework.boot - spring-boot-starter-web - ${spring-boot.version} - - - org.springframework.boot - spring-boot-starter-security - ${spring-boot.version} - - - org.springframework.boot - spring-boot-starter-tomcat - ${spring-boot.version} - provided - - - org.springframework.boot - spring-boot-starter-data-jpa - ${spring-boot.version} - - - org.springframework.boot - spring-boot-starter-validation - ${spring-boot.version} - - - org.springframework.boot - spring-boot-starter-websocket - ${spring-boot.version} - - - org.springframework.boot - spring-boot-starter-jersey - ${spring-boot.version} - - - jersey-bean-validation - org.glassfish.jersey.ext - - - bean-validator - org.glassfish.hk2.external - - - - - org.springframework.boot - spring-boot-devtools - ${spring-boot.version} - - - - - org.glassfish.jersey.media - jersey-media-multipart - ${jersey.version} - - - com.fasterxml.jackson.datatype - jackson-datatype-hibernate5 - ${jackson-datatype.version} - - - com.fasterxml.jackson.module - jackson-module-jaxb-annotations - ${jackson-datatype.version} - - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 - ${jackson-datatype.version} - - - - - org.postgresql - postgresql - ${postgresql.version} - runtime - - - com.vladmihalcea - hibernate-types-52 - ${hibernate-types-52.version} - - - org.flywaydb - flyway-core - ${flyway.version} - - - - - com.github.java-json-tools - json-schema-validator - ${json-schema-validator.version} - - - commons-io - commons-io - ${commons-io.version} - - - org.apache.commons - commons-text - ${commons-text.version} - - - - - javax.xml.bind - jaxb-api - ${jaxb.version} - - - - - org.bitbucket.b_c - jose4j - ${jose4j.version} - - - - - org.apache.shiro - shiro-core - ${shiro.version} - - - - - org.jsoup - jsoup - ${jsoup.version} - - - - - com.jayway.jsonpath - json-path - ${json-path.version} - - - - - io.reactivex.rxjava3 - rxjava - ${rxjava.version} - - - - - net.automatalib.distribution - automata-distribution - ${automatalib.version} - pom - - - - - de.learnlib.distribution - learnlib-distribution - ${learnlib.version} - pom - - - - - org.seleniumhq.selenium - selenium-java - ${selenium.version} - - - - xml-apis - xml-apis - ${xml-apis.version} - - - - - org.springframework.boot - spring-boot-starter-test - ${spring-boot.version} - - - org.junit.jupiter - junit-jupiter-engine - - - - - org.junit.jupiter - junit-jupiter-engine - ${junit.version} - test - - - org.junit.jupiter - junit-jupiter-params - ${junit.version} - test - - - org.mockito - mockito-core - ${mockito.version} - test - - - org.mockito - mockito-junit-jupiter - ${mockito.version} - test - - - org.testcontainers - junit-jupiter - ${testcontainers.version} - test - - - org.testcontainers - postgresql - ${testcontainers.version} - test - - - org.awaitility - awaitility - ${awaitility.version} - test - - - - - - ALEX-${project.version} - - - - org.springframework.boot - spring-boot-maven-plugin - ${spring-boot.version} - - de.learnlib.alex.AlexApp - false - false - - - - - repackage - - - exec - - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - ${surefire-plugin.version} - - ${surefire.skip} - - - java.util.logging.manager - org.apache.logging.log4j.jul.LogManager - - - - - - - - org.apache.maven.plugins - maven-failsafe-plugin - ${failsafe-plugin.version} - - - - java.util.logging.manager - org.apache.logging.log4j.LogManager - - - ${project.build.outputDirectory} - - **/integrationtests/websocket/**/*.java - **/integrationtests/resources/LearnerResourceIT.java - - - - - - integration-test - verify - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - ${compiler-plugin.version} - - - - org.apache.maven.plugins - maven-dependency-plugin - ${dependency-plugin.version} - - - - org.eluder.coveralls - coveralls-maven-plugin - ${coveralls-plugin.version} - - - javax.xml.bind - jaxb-api - 2.4.0-b180830.0359 - - - - - - - org.codehaus.mojo - versions-maven-plugin - ${versions-plugin.version} - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - jar-with-dependencies - - - - - make-assembly - package - - single - - - - - - - - - - code-analysis - - - - - - org.jacoco - jacoco-maven-plugin - ${jacoco-plugin.version} - - - pre-unit-test - - prepare-agent - - - - post-unit-test - - report - - - - - - - - com.github.spotbugs - spotbugs-maven-plugin - ${maven-spotbugs.version} - - Max - Low - false - - - - com.github.spotbugs - spotbugs - ${spotbugs.version} - - - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - ${maven-checkstyle.version} - - - com.puppycrawl.tools - checkstyle - ${checkstyle.version} - - - - src/main/resources/checkstyle.xml - src/main/resources/checkstyle-suppressions.xml - UTF-8 - true - false - false - false - - - - verify - verify - - check - - - true - 50 - - - - - - - - - - diff --git a/backend/src/main/java/de/learnlib/alex/AlexApp.java b/backend/src/main/java/de/learnlib/alex/AlexApp.java deleted file mode 100644 index 926258b3f..000000000 --- a/backend/src/main/java/de/learnlib/alex/AlexApp.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.transaction.annotation.EnableTransactionManagement; - -/** - * The entry point to ALEX. - */ -@SpringBootApplication -@EnableTransactionManagement -@EnableScheduling -public class AlexApp extends SpringBootServletInitializer { - - /** - * Starts the standalone version of ALEX. - * - * @param args - * Additional commandline parameters. - */ - public static void main(String[] args) { - SpringApplication.run(AlexApp.class, args); - } -} - diff --git a/backend/src/main/java/de/learnlib/alex/AlexComponent.java b/backend/src/main/java/de/learnlib/alex/AlexComponent.java deleted file mode 100644 index 6e5a0f959..000000000 --- a/backend/src/main/java/de/learnlib/alex/AlexComponent.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex; - -import de.learnlib.alex.auth.dao.UserDAO; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.auth.entities.UserRole; -import de.learnlib.alex.learning.dao.LearnerResultDAO; -import de.learnlib.alex.settings.dao.SettingsDAO; -import de.learnlib.alex.settings.entities.DriverSettings; -import de.learnlib.alex.settings.entities.Settings; -import de.learnlib.alex.testing.dao.TestReportDAO; -import java.io.IOException; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Paths; -import javax.annotation.PostConstruct; -import javax.validation.ValidationException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.core.env.Environment; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.cors.CorsConfiguration; -import org.springframework.web.cors.CorsConfigurationSource; -import org.springframework.web.cors.UrlBasedCorsConfigurationSource; - -@Component -public class AlexComponent { - - private final Environment env; - private final UserDAO userDAO; - private final SettingsDAO settingsDAO; - private final TestReportDAO testReportDAO; - private final LearnerResultDAO learnerResultDAO; - - @Value("${runtime}") - String runtime; - - @Autowired - public AlexComponent(Environment env, - UserDAO userDAO, - SettingsDAO settingsDAO, - TestReportDAO testReportDAO, - LearnerResultDAO learnerResultDAO) { - this.env = env; - this.userDAO = userDAO; - this.settingsDAO = settingsDAO; - this.testReportDAO = testReportDAO; - this.learnerResultDAO = learnerResultDAO; - } - - /** - * Create an admin at the start of th ALEX if no admin is currently in the DB. - */ - @PostConstruct - @Transactional(rollbackFor = Exception.class) - public void createDefaultAdmin() { - if (userDAO.getAllByRole(UserRole.ADMIN).size() == 0) { - User admin = new User(); - admin.setEmail(env.getProperty("alex.admin.email")); - admin.setUsername(env.getProperty("alex.admin.username")); - admin.setRole(UserRole.ADMIN); - admin.setPassword(new BCryptPasswordEncoder().encode(env.getProperty("alex.admin.password"))); - userDAO.create(admin); - } - } - - @PostConstruct - public void abortActiveTestReports() { - testReportDAO.abortActiveTestReports(); - } - - @PostConstruct - public void abortActiveLearnerResults() { - learnerResultDAO.abortActiveLearnerResults(); - } - - @PostConstruct - public void configureLtsMin() { - final String ltsminBinDir = env.getProperty("ltsmin.path"); - if (ltsminBinDir != null && !ltsminBinDir.trim().equals("")) { - if (!Files.isDirectory(Paths.get(ltsminBinDir))) { - System.err.println("Cannot find directory for ltsmin binaries."); - System.exit(0); - } else { - System.setProperty("automatalib.ltsmin.path", ltsminBinDir); - } - } - } - - @PostConstruct - public void createSystemFilesDirectory() { - try { - final var path = env.getProperty("alex.filesRootDir"); - final var systemPath = Paths.get(path, "system"); - if (Files.notExists(systemPath)) { - Files.createDirectories(systemPath); - } - } catch (IOException e) { - System.err.println("Failed to initialize system files directory."); - System.exit(0); - } - } - - /** - * Initialize system properties and create the settings object if needed. - */ - @PostConstruct - @Transactional - public void initializeSettings() { - var settings = settingsDAO.get(); - - // create settings for the first time - if (settings == null) { - try { - settings = new Settings(); - final var remoteDriverURL = getWebdriverUrl(); - final var driverSettings = new DriverSettings(); - driverSettings.setRemote(remoteDriverURL); - settings.setDriverSettings(driverSettings); - settingsDAO.create(settings); - } catch (ValidationException e) { - e.printStackTrace(); - System.exit(0); - } - } - - try { - settings.setRuntime(runtime); - settingsDAO.update(settings); - - final var remoteDriverUrl = getWebdriverUrl(); - if (!remoteDriverUrl.isEmpty()) { - new URL(remoteDriverUrl); - settings.getDriverSettings().setRemote(remoteDriverUrl); - settingsDAO.update(settings); - } - } catch (Exception e) { - e.printStackTrace(); - System.exit(0); - } - } - - @Bean - public PasswordEncoder encoder() { - return new BCryptPasswordEncoder(); - } - - /** - * Allow requests from a all origins. - * - * @return The bean. - */ - @Bean - public CorsConfigurationSource corsConfigurationSource() { - final CorsConfiguration config = new CorsConfiguration(); - config.setAllowCredentials(true); - config.addAllowedOriginPattern("*"); - config.addAllowedHeader("*"); - config.addAllowedMethod("*"); - - final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - source.registerCorsConfiguration("/**", config); - - return source; - } - - private String getWebdriverUrl() { - return "http://" - + env.getProperty("selenium.grid.host", "") - + ":" - + env.getProperty("selenium.grid.port", "") - + "/wd/hub"; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/JacksonConfiguration.java b/backend/src/main/java/de/learnlib/alex/JacksonConfiguration.java deleted file mode 100644 index 266d99661..000000000 --- a/backend/src/main/java/de/learnlib/alex/JacksonConfiguration.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * Jersey Provide to customise the Jackson ObjectMapper. - */ -@Configuration -public class JacksonConfiguration { - - /** - * Default constructor, which creates the ObjectMapper and add the custom modules. - */ - @Bean - public ObjectMapper objectMapper() { - final var hibernate5Module = new Hibernate5Module(); - hibernate5Module.configure(Hibernate5Module.Feature.USE_TRANSIENT_ANNOTATION, false); - - final var javaTimeModule = new JavaTimeModule(); - - final var mapper = new ObjectMapper(); - mapper.registerModule(hibernate5Module); - mapper.registerModule(javaTimeModule); - return mapper; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/RedirectConfig.java b/backend/src/main/java/de/learnlib/alex/RedirectConfig.java deleted file mode 100644 index 247782e56..000000000 --- a/backend/src/main/java/de/learnlib/alex/RedirectConfig.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex; - -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -@Configuration -public class RedirectConfig implements WebMvcConfigurer { - - @Override - public void addViewControllers(ViewControllerRegistry reg) { - redirect(reg, "/app/**", "/login", "/logout", "/error"); - } - - private void redirect(ViewControllerRegistry reg, String... routes) { - for (int i = 0; i < routes.length; i++) { - reg.addViewController(routes[i]).setViewName("forward:/index.html"); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/auth/dao/UserDAO.java b/backend/src/main/java/de/learnlib/alex/auth/dao/UserDAO.java deleted file mode 100644 index 402e2542d..000000000 --- a/backend/src/main/java/de/learnlib/alex/auth/dao/UserDAO.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.auth.dao; - -import de.learnlib.alex.auth.entities.UpdateMaxAllowedProcessesInput; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.auth.entities.UserRole; -import de.learnlib.alex.auth.repositories.UserRepository; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.dao.FileDAO; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.websocket.services.WebSocketService; -import java.io.IOException; -import java.util.List; -import javax.persistence.EntityManager; -import javax.validation.ValidationException; -import org.hibernate.validator.internal.constraintvalidators.hv.EmailValidator; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -/** - * Implementation of a UserDAO using Hibernate. - */ -@Service -@Transactional(rollbackFor = Exception.class) -public class UserDAO { - - private static final Logger logger = LoggerFactory.getLogger(UserDAO.class); - - private static final int MAX_USERNAME_LENGTH = 32; - - private final UserRepository userRepository; - private final FileDAO fileDAO; - private final ProjectDAO projectDAO; - private final ProjectRepository projectRepository; - private final WebSocketService webSocketService; - private final EntityManager entityManager; - - @Autowired - public UserDAO( - UserRepository userRepository, - FileDAO fileDAO, - ProjectDAO projectDAO, - ProjectRepository projectRepository, - @Lazy WebSocketService webSocketService, - EntityManager entityManager - ) { - this.userRepository = userRepository; - this.fileDAO = fileDAO; - this.projectDAO = projectDAO; - this.projectRepository = projectRepository; - this.webSocketService = webSocketService; - this.entityManager = entityManager; - } - - public User create(User newUser) { - if (userRepository.findOneByEmail(newUser.getEmail()).isPresent()) { - throw new ValidationException("A user with the email already exists"); - } - - if (userRepository.findOneByUsername(newUser.getUsername()).isPresent()) { - throw new ValidationException("A user with this username already exists"); - } - - if (!new EmailValidator().isValid(newUser.getEmail(), null)) { - throw new ValidationException("The email is not valid"); - } - - if (newUser.getUsername().length() > MAX_USERNAME_LENGTH - || !newUser.getUsername().matches("^[a-zA-Z][a-zA-Z0-9]*$")) { - throw new ValidationException("The username is not valid!"); - } - - return userRepository.save(newUser); - } - - public List getAll() { - return userRepository.findAll(); - } - - public List getAllByRole(UserRole role) { - return userRepository.findByRole(role); - } - - public User getByID(Long id) throws NotFoundException { - return userRepository.findById(id).orElseThrow(() -> - new NotFoundException("Could not find the user with the ID " + id + ".") - ); - } - - public User getByEmail(String email) { - return userRepository.findOneByEmail(email).orElseThrow(() -> - new NotFoundException("Could not find the user with the email '" + email + "'!") - ); - } - - public User getByUsername(String username) { - return userRepository.findOneByUsername(username).orElseThrow(() -> - new NotFoundException("Could not find the user with username'" + username + "'!") - ); - } - - public User update(User user) { - return userRepository.save(user); - } - - public void delete(User authUser, Long id) { - delete(authUser, getByID(id)); - } - - public void delete(User authUser, List userIds) { - final List users = userRepository.findAllByIdIn(userIds); - if (users.size() != userIds.size()) { - throw new NotFoundException("At least one user could not be found."); - } - - for (User user : users) { - delete(authUser, user); - entityManager.flush(); - } - } - - public User updateMaxAllowedProcesses(User user, UpdateMaxAllowedProcessesInput input) { - final var userInDB = userRepository.findById(user.getId()) - .orElseThrow(() -> new NotFoundException("The user could not be found.")); - - userInDB.setMaxAllowedProcesses(input.maxAllowedProcesses); - - return userRepository.save(userInDB); - } - - private void delete(User authUser, User user) { - // make sure there is at least one registered admin - if (user.getRole().equals(UserRole.ADMIN)) { - List admins = userRepository.findByRole(UserRole.ADMIN); - - if (admins.size() == 1) { - throw new NotFoundException("There has to be at least one admin left"); - } - } - - // remove user from all projects in which he is a member - for (final Project project : user.getProjectsMember()) { - project.getMembers().removeIf(u -> u.getId().equals(user.getId())); - projectRepository.save(project); - } - - // remove user from all projects in which he is an owner - for (final Project project : user.getProjectsOwner()) { - project.getOwners().removeIf(u -> u.getId().equals(user.getId())); - projectRepository.save(project); - - //remove the project if there is none owner left - if (project.getOwners().isEmpty()) { - - projectDAO.delete(authUser, project.getId()); - try { - fileDAO.deleteProjectDirectory(user, project.getId()); - } catch (IOException e) { - logger.info("The project has been deleted, the user directory, however, not."); - } - } - } - - userRepository.delete(user); - - //close all active webSocketSessions of user and lift all corresponding locks - webSocketService.closeAllUserSessions(user.getId()); - - // delete the user directory - try { - fileDAO.deleteUserDirectory(user); - } catch (IOException e) { - logger.info("The user has been deleted, the user directory, however, not."); - } - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/auth/entities/JsonWebToken.java b/backend/src/main/java/de/learnlib/alex/auth/entities/JsonWebToken.java deleted file mode 100644 index d91035bf2..000000000 --- a/backend/src/main/java/de/learnlib/alex/auth/entities/JsonWebToken.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.auth.entities; - -public class JsonWebToken { - - private String token; - - public JsonWebToken() { - } - - public JsonWebToken(String token) { - this.token = token; - } - - public String getToken() { - return token; - } - - public void setToken(String token) { - this.token = token; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/auth/entities/UpdateEmailInput.java b/backend/src/main/java/de/learnlib/alex/auth/entities/UpdateEmailInput.java deleted file mode 100644 index 1424ebc5e..000000000 --- a/backend/src/main/java/de/learnlib/alex/auth/entities/UpdateEmailInput.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.auth.entities; - -import javax.validation.constraints.Email; -import javax.validation.constraints.NotBlank; - -public class UpdateEmailInput { - - @NotBlank(message = "The email must not be blank.") - @Email(message = "The value is not a valid email.") - private String email; - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/auth/entities/UpdateMaxAllowedProcessesInput.java b/backend/src/main/java/de/learnlib/alex/auth/entities/UpdateMaxAllowedProcessesInput.java deleted file mode 100644 index 0e242bf4f..000000000 --- a/backend/src/main/java/de/learnlib/alex/auth/entities/UpdateMaxAllowedProcessesInput.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.auth.entities; - -import javax.validation.constraints.Min; - -public class UpdateMaxAllowedProcessesInput { - - @Min(value = 1, message = "The number of allowed processes has to be greater than 0.") - public int maxAllowedProcesses = 1; -} diff --git a/backend/src/main/java/de/learnlib/alex/auth/entities/UpdatePasswordInput.java b/backend/src/main/java/de/learnlib/alex/auth/entities/UpdatePasswordInput.java deleted file mode 100644 index fbc49ffa6..000000000 --- a/backend/src/main/java/de/learnlib/alex/auth/entities/UpdatePasswordInput.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.auth.entities; - -import javax.validation.constraints.NotBlank; - -public class UpdatePasswordInput { - - @NotBlank(message = "The new password must not be empty.") - private String newPassword; - - @NotBlank(message = "The old password must not be empty.") - private String oldPassword; - - public String getNewPassword() { - return newPassword; - } - - public void setNewPassword(String newPassword) { - this.newPassword = newPassword; - } - - public String getOldPassword() { - return oldPassword; - } - - public void setOldPassword(String oldPassword) { - this.oldPassword = oldPassword; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/auth/entities/UpdateRoleInput.java b/backend/src/main/java/de/learnlib/alex/auth/entities/UpdateRoleInput.java deleted file mode 100644 index 660316c01..000000000 --- a/backend/src/main/java/de/learnlib/alex/auth/entities/UpdateRoleInput.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.auth.entities; - -import javax.validation.constraints.NotNull; - -public class UpdateRoleInput { - - @NotNull(message = "The role must not be null.") - private UserRole role; - - public UserRole getRole() { - return role; - } - - public void setRole(UserRole role) { - this.role = role; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/auth/entities/UpdateUsernameInput.java b/backend/src/main/java/de/learnlib/alex/auth/entities/UpdateUsernameInput.java deleted file mode 100644 index c6f68f8a8..000000000 --- a/backend/src/main/java/de/learnlib/alex/auth/entities/UpdateUsernameInput.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.auth.entities; - -import de.learnlib.alex.auth.rest.UserResource; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; - -public class UpdateUsernameInput { - - @NotBlank(message = "The username must not be blank.") - @Pattern( - regexp = "^[a-zA-Z][a-zA-Z0-9]*$", - message = "The username must start with a letter followed by letters or numbers." - ) - @Size( - min = 1, - max = UserResource.MAX_USERNAME_LENGTH, - message = "The username can only contain " + UserResource.MAX_USERNAME_LENGTH + " characters." - ) - private String username; - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/auth/entities/User.java b/backend/src/main/java/de/learnlib/alex/auth/entities/User.java deleted file mode 100644 index 8c478a907..000000000 --- a/backend/src/main/java/de/learnlib/alex/auth/entities/User.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.auth.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.webhooks.entities.Webhook; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.ManyToMany; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.validation.constraints.Email; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotBlank; -import org.hibernate.annotations.Cascade; - -/** - * The model for a user. - */ -@Entity -@Table(name = "user", schema = "public") -public class User implements Serializable { - - /** Auto generated id for saving it into the db. */ - private static final long serialVersionUID = -3567360676364330143L; - - /** The unique id of the user. */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - /** The username of the user. */ - @Column(unique = true) - private String username; - - /** The email address of the user he uses to login. */ - @NotBlank - @Email - @Column(unique = true) - private String email; - - /** The hash of the users password. */ - @NotBlank - private String password; - - /** The role of the user. */ - private UserRole role; - - /** The set of projects in which the user is an owner. */ - @ManyToMany(mappedBy = "owners") - @JsonIgnore - private Set projectsOwner; - - /** The set of projects in which the user is a member. */ - @ManyToMany(mappedBy = "members") - @JsonIgnore - private Set projectsMember; - - /** The list of webhooks. */ - @OneToMany(mappedBy = "user") - @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.REMOVE}) - @JsonIgnore - private List webhooks; - - @Min(value = 1, message = "The number of allowed processes has to be greater than 0.") - private int maxAllowedProcesses; - - /** - * Default constructor that gives the user the role of "registered". - */ - public User() { - this.projectsOwner = new HashSet<>(); - this.projectsMember = new HashSet<>(); - this.webhooks = new ArrayList<>(); - this.role = UserRole.REGISTERED; - this.maxAllowedProcesses = 1; - } - - /** - * Constructor that sets a specific ID and gives the user the role of "registered". - * - * @param id - * The ID of the User. - */ - public User(Long id) { - this(); - this.id = id; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public UserRole getRole() { - return role; - } - - public void setRole(UserRole role) { - this.role = role; - } - - public Set getProjectsOwner() { - return projectsOwner; - } - - public void setProjectsOwner(Set projectsOwner) { - this.projectsOwner = projectsOwner; - } - - public Set getProjectsMember() { - return projectsMember; - } - - public void setProjectsMember(Set projectsMember) { - this.projectsMember = projectsMember; - } - - @JsonIgnore - public String getPassword() { - return password; - } - - @JsonIgnore - public void setPassword(String password) { - this.password = password; - } - - public List getWebhooks() { - return webhooks; - } - - public void setWebhooks(List webhooks) { - this.webhooks = webhooks; - } - - public void setMaxAllowedProcesses(int maxAllowedProcesses) { - this.maxAllowedProcesses = maxAllowedProcesses; - } - - public int getMaxAllowedProcesses() { - return this.maxAllowedProcesses; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof User)) { - return false; - } - User user = (User) o; - return Objects.equals(id, user.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } - - @Override - public String toString() { - return "User{" - + "id=" + id - + ", username='" + username + '\'' - + ", email='" + email + '\'' - + ", role=" + role - + '}'; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/auth/entities/UserRole.java b/backend/src/main/java/de/learnlib/alex/auth/entities/UserRole.java deleted file mode 100644 index d332de3db..000000000 --- a/backend/src/main/java/de/learnlib/alex/auth/entities/UserRole.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.auth.entities; - -/** - * Enumeration for User roles. - */ -public enum UserRole { - - ANONYMOUS, - - /** - * User is default registered user. - */ - REGISTERED, - - /** - * User is administrator with higher privileges. - */ - ADMIN -} diff --git a/backend/src/main/java/de/learnlib/alex/auth/events/UserEvent.java b/backend/src/main/java/de/learnlib/alex/auth/events/UserEvent.java deleted file mode 100644 index 37d00f786..000000000 --- a/backend/src/main/java/de/learnlib/alex/auth/events/UserEvent.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.auth.events; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.webhooks.entities.Event; -import de.learnlib.alex.webhooks.entities.EventType; - -/** Events for users. */ -public class UserEvent { - - /** Event for when the subscribing user is deleted. */ - public static class Deleted extends Event { - - /** - * Constructor. - * - * @param id - * The id of the user that has been deleted. - */ - public Deleted(Long id) { - super(id, EventType.USER_DELETED); - } - } - - /** Event for when the credentials of the subscribing have changed. */ - public static class CredentialsUpdated extends Event { - - /** - * Constructor. - * - * @param id - * The id of the user whose credentials have changed. - */ - public CredentialsUpdated(Long id) { - super(id, EventType.USER_CREDENTIALS_UPDATED); - } - } - - /** Event for when the role of the subscribing user has changed. */ - public static class RoleUpdated extends Event { - - /** - * Constructor. - * - * @param user - * The user whose role has changed. - */ - public RoleUpdated(User user) { - super(user, EventType.USER_ROLE_UPDATED); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/auth/inputs/CreateUserInput.java b/backend/src/main/java/de/learnlib/alex/auth/inputs/CreateUserInput.java deleted file mode 100644 index fad459b82..000000000 --- a/backend/src/main/java/de/learnlib/alex/auth/inputs/CreateUserInput.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.auth.inputs; - -import javax.validation.constraints.Email; -import javax.validation.constraints.NotEmpty; - -public class CreateUserInput { - - @NotEmpty - public String username; - - @Email - @NotEmpty - public String email; - - @NotEmpty - public String password; -} diff --git a/backend/src/main/java/de/learnlib/alex/auth/inputs/LoginInput.java b/backend/src/main/java/de/learnlib/alex/auth/inputs/LoginInput.java deleted file mode 100644 index b81c36f3b..000000000 --- a/backend/src/main/java/de/learnlib/alex/auth/inputs/LoginInput.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.auth.inputs; - -import javax.validation.constraints.NotEmpty; - -public class LoginInput { - - @NotEmpty - public String email; - - @NotEmpty - public String password; -} diff --git a/backend/src/main/java/de/learnlib/alex/auth/repositories/UserRepository.java b/backend/src/main/java/de/learnlib/alex/auth/repositories/UserRepository.java deleted file mode 100644 index 30a09a009..000000000 --- a/backend/src/main/java/de/learnlib/alex/auth/repositories/UserRepository.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.auth.repositories; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.auth.entities.UserRole; -import java.util.List; -import java.util.Optional; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** - * Repository to persist Users. - */ -@Repository -public interface UserRepository extends JpaRepository { - - /** - * Find all users by their role. - * - * @param role - * The role to look for. - * @return All users with that role. - */ - List findByRole(UserRole role); - - /** - * Find a User by its email. - * - * @param email - * The email to look for. - * @return The users with that email or null. - */ - Optional findOneByEmail(String email); - - /** - * Find a User by its username. - * - * @param username - * The username to look for. - * @return The users with that username or null. - */ - Optional findOneByUsername(String username); - - /** - * Find multiple users by IDs. - * - * @param userIds - * The IDs of the users to get. - * @return The matching users. - */ - List findAllByIdIn(List userIds); -} diff --git a/backend/src/main/java/de/learnlib/alex/auth/rest/UserResource.java b/backend/src/main/java/de/learnlib/alex/auth/rest/UserResource.java deleted file mode 100644 index 70dd35e30..000000000 --- a/backend/src/main/java/de/learnlib/alex/auth/rest/UserResource.java +++ /dev/null @@ -1,492 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.auth.rest; - -import de.learnlib.alex.auth.dao.UserDAO; -import de.learnlib.alex.auth.entities.JsonWebToken; -import de.learnlib.alex.auth.entities.UpdateEmailInput; -import de.learnlib.alex.auth.entities.UpdateMaxAllowedProcessesInput; -import de.learnlib.alex.auth.entities.UpdatePasswordInput; -import de.learnlib.alex.auth.entities.UpdateRoleInput; -import de.learnlib.alex.auth.entities.UpdateUsernameInput; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.auth.entities.UserRole; -import de.learnlib.alex.auth.events.UserEvent; -import de.learnlib.alex.auth.inputs.CreateUserInput; -import de.learnlib.alex.auth.inputs.LoginInput; -import de.learnlib.alex.common.exceptions.ForbiddenOperationException; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.security.AuthContext; -import de.learnlib.alex.security.JwtHelper; -import de.learnlib.alex.settings.dao.SettingsDAO; -import de.learnlib.alex.settings.entities.Settings; -import de.learnlib.alex.webhooks.services.WebhookService; -import java.util.ArrayList; -import java.util.List; -import javax.validation.ValidationException; -import javax.ws.rs.core.MediaType; -import org.apache.shiro.authz.UnauthorizedException; -import org.hibernate.validator.internal.constraintvalidators.hv.EmailValidator; -import org.jose4j.lang.JoseException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -/** - * REST resource to handle users. - */ -@RestController -@RequestMapping("/rest/users") -public class UserResource { - - public static final int MAX_USERNAME_LENGTH = 32; - - private final AuthContext authContext; - private final UserDAO userDAO; - private final WebhookService webhookService; - private final SettingsDAO settingsDAO; - private final PasswordEncoder passwordEncoder; - - @Autowired - public UserResource( - AuthContext authContext, - UserDAO userDAO, - WebhookService webhookService, - SettingsDAO settingsDAO, - PasswordEncoder passwordEncoder - ) { - this.authContext = authContext; - this.userDAO = userDAO; - this.webhookService = webhookService; - this.settingsDAO = settingsDAO; - this.passwordEncoder = passwordEncoder; - } - - /** - * Creates a new user. - * - * @param input - * The user to create - * @return The created user (enhanced with information form the DB); an error message on failure. - */ - @PostMapping( - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity create(@RequestBody CreateUserInput input) { - final User user = authContext.getUser(); - - if (!new EmailValidator().isValid(input.email, null)) { - throw new ValidationException("The email is not valid"); - } - - if (input.username.length() > MAX_USERNAME_LENGTH || !input.username.matches("^[a-zA-Z][a-zA-Z0-9]*$")) { - throw new ValidationException("The username is not valid!"); - } - - if (usernameIsAlreadyTaken(input.username)) { - throw new ValidationException("The username is already taken!"); - } - - final Settings settings = settingsDAO.get(); - - final var newUser = new User(); - newUser.setEmail(input.email); - newUser.setUsername(input.username); - newUser.setPassword(passwordEncoder.encode(input.password)); - newUser.setRole(UserRole.REGISTERED); - - if (user.getId() == null) { // anonymous registration - if (!settings.isAllowUserRegistration()) { - throw new ForbiddenOperationException("Public user registration is not allowed."); - } - userDAO.create(newUser); - return ResponseEntity.status(HttpStatus.CREATED).body(newUser); - } else { - if (user.getRole().equals(UserRole.REGISTERED)) { - throw new UnauthorizedException("You are not allowed to create new accounts."); - } else { - userDAO.create(newUser); - return ResponseEntity.status(HttpStatus.CREATED).body(newUser); - } - } - } - - /** - * Get the account information about one user. This only works for your own account or if you are an administrator. - * - * @param userId - * The ID of the user. - * @return Detailed information about the user. - */ - @GetMapping( - value = "/{id}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity get(@PathVariable("id") Long userId) { - final User user = authContext.getUser(); - if (!user.getRole().equals(UserRole.ADMIN) && !user.getId().equals(userId)) { - throw new ForbiddenOperationException("You are not allowed to get this information."); - } - - final User userById = userDAO.getByID(userId); - return ResponseEntity.ok(userById); - } - - /** - * Get the account information about multiple users. - * - * @param userIds - * The ids of the users. - * @return Detailed information about the users. - */ - @GetMapping( - value = "/batch/{ids}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> getManyUsers(@PathVariable("ids") List userIds) { - final List users = new ArrayList<>(); - for (Long id : userIds) { - users.add(userDAO.getByID(id)); - } - - return ResponseEntity.ok(users); - } - - /** - * Get all users. This is only allowed for admins. - * - * @return A list of all users. This list can be empty. - */ - @GetMapping( - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> getAll() { - final List users = userDAO.getAll(); - return ResponseEntity.ok(users); - } - - @GetMapping( - value = "/search", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> getByUsernameOrEmail(@RequestParam("searchterm") String term) { - final List users = new ArrayList<>(); - try { - if (term.contains("@")) { - users.add(userDAO.getByEmail(term)); - } else { - users.add(userDAO.getByUsername(term)); - } - } catch (NotFoundException ignored) { - } - return ResponseEntity.ok(users); - } - - @PutMapping( - value = "/{id}/processes", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity changeMaxAllowedProcesses( - @PathVariable("id") Long userId, - @Validated @RequestBody UpdateMaxAllowedProcessesInput input - ) { - final var user = authContext.getUser(); - final var updatedUser = userDAO.updateMaxAllowedProcesses(user, input); - return ResponseEntity.ok(updatedUser); - } - - - /** - * Changes the password of the user. - * - * @param userId - * The id of the user - * @param input - * The pair of oldPassword and newPassword as json - * @return The updated user. - */ - @PutMapping( - value = "/{id}/password", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity changePassword( - @PathVariable("id") Long userId, - @Validated @RequestBody UpdatePasswordInput input - ) { - final var user = authContext.getUser(); - if (!user.getId().equals(userId)) { - throw new ForbiddenOperationException("You are not allowed to do this."); - } - - final var realUser = userDAO.getByID(userId); - if (!passwordEncoder.matches(input.getOldPassword(), realUser.getPassword())) { - throw new ValidationException("Please provide your old password!"); - } - - realUser.setPassword(passwordEncoder.encode(input.getNewPassword())); - - final var updatedUser = userDAO.update(realUser); - - webhookService.fireEvent(user, new UserEvent.CredentialsUpdated(userId)); - return ResponseEntity.ok(updatedUser); - } - - /** - * Changes the email of the user. This can only be invoked for your own account or if you are an administrator. - * Please also note: Your new email must not be your current one and no other user should already have this email. - * - * @param userId - * The id of the user - * @param input - * The input with the new email. - * @return The updated user. - */ - @PutMapping( - value = "/{id}/email", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity changeEmail( - @PathVariable("id") Long userId, - @Validated @RequestBody UpdateEmailInput input - ) { - final User user = authContext.getUser(); - - if (!user.getId().equals(userId) && !user.getRole().equals(UserRole.ADMIN)) { - throw new UnauthorizedException("You are not allowed to do this."); - } - - if (emailIsAlreadyTaken(input.getEmail())) { - throw new ValidationException("The email is already taken!"); - } - - final var realUser = userDAO.getByID(userId); - realUser.setEmail(input.getEmail()); - - final var updatedUser = userDAO.update(realUser); - - webhookService.fireEvent(user, new UserEvent.CredentialsUpdated(userId)); - return ResponseEntity.ok(updatedUser); - } - - /** - * Changes the username of the user. This can only be invoked if you are an administrator. - * Your new username must not be your current one and no other user should already have this username. - * - * @param userId - * The id of the user. - * @param input - * The input with a new username. - * @return The updated user. - */ - @PutMapping( - value = "/{id}/username", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity changeUsername( - @PathVariable("id") Long userId, - @Validated @RequestBody UpdateUsernameInput input - ) { - final var user = authContext.getUser(); - - if (!user.getRole().equals(UserRole.ADMIN)) { - throw new ForbiddenOperationException("You are not allowed to do this."); - } else if (usernameIsAlreadyTaken(input.getUsername())) { - throw new ValidationException("The username is already taken!"); - } - - final var userInDB = userDAO.getByID(userId); - userInDB.setUsername(input.getUsername()); - - final var updatedUser = userDAO.update(userInDB); - - webhookService.fireEvent(user, new UserEvent.CredentialsUpdated(userId)); - return ResponseEntity.ok(updatedUser); - } - - /** - * Update the role of a user. - * - * @param userId - * The ID of the user to update. - * @param input - * The input with the new role. - * @return The updated user. - */ - @PutMapping( - value = "/{id}/role", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity changeRole( - @PathVariable("id") Long userId, - @Validated @RequestBody UpdateRoleInput input - ) { - final User user = authContext.getUser(); - final User userToUpdate = userDAO.getByID(userId); - - switch (input.getRole()) { - case ADMIN: - userToUpdate.setRole(input.getRole()); - break; - case REGISTERED: - // if the admin wants to revoke his own rights - // -> take care that always one admin is in the system - if (user.getId().equals(userId)) { - final List admins = userDAO.getAllByRole(UserRole.ADMIN); - if (admins.size() == 1) { - throw new ValidationException("The only admin left cannot take away his own admin rights!"); - } - } - userToUpdate.setRole(UserRole.REGISTERED); - break; - default: - throw new ValidationException("Cannot update role."); - } - - final var updatedUser = userDAO.update(userToUpdate); - webhookService.fireEvent(user, new UserEvent.RoleUpdated(updatedUser)); - return ResponseEntity.ok(updatedUser); - } - - /** - * Delete an user. This is only allowed for your own account or if you are an administrator. - * - * @param userId - * The ID of the user to delete. - * @return Nothing if the user was deleted. - */ - @DeleteMapping( - value = "/{id}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity delete(@PathVariable("id") Long userId) { - final User user = authContext.getUser(); - - if (!user.getId().equals(userId) && !user.getRole().equals(UserRole.ADMIN)) { - throw new ForbiddenOperationException("You are not allowed to delete this user."); - } - - // the event is not fired if we do it after the user is deleted in the next line - // since all webhooks registered to the user are deleted as well. - webhookService.fireEvent(new User(userId), new UserEvent.Deleted(userId)); - userDAO.delete(user, userId); - - return ResponseEntity.noContent().build(); - } - - /** - * Deletes multiples users. An admin cannot delete himself. - * - * @param ids - * The ids of the user to delete. - * @return Nothing if the users have been deleted. - */ - @DeleteMapping( - value = "/batch/{ids}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity delete(@PathVariable("ids") List ids) { - final User user = authContext.getUser(); - - if (ids.contains(user.getId())) { - throw new IllegalArgumentException("You cannot delete your own account this way."); - } - - userDAO.delete(user, ids); - - ids.forEach(id -> webhookService.fireEvent(new User(id), new UserEvent.Deleted(id))); - return ResponseEntity.noContent().build(); - } - - /** - * Logs in a user by generating a unique JWT for him that needs to be send in every request. - * - * @param input - * The user to login - * @return If the user was successfully logged in: a JSON Object with the authentication token as only field. - */ - @PostMapping( - value = "/login", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity login(@Validated @RequestBody LoginInput input) { - try { - final var user = userDAO.getByEmail(input.email); - - if (!passwordEncoder.matches(input.password, user.getPassword())) { - throw new IllegalArgumentException("Please provide your correct password!"); - } - - final var jwt = new JsonWebToken(JwtHelper.generateJWT(user)); - - return ResponseEntity.ok(jwt); - } catch (JoseException e) { - throw new UnauthorizedException(); - } - } - - /** - * Get the current logged in user. - * - * @return The user. - */ - @GetMapping( - value = "/myself", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity myself() { - final User user = authContext.getUser(); - - final User myself = userDAO.getByID(user.getId()); - return ResponseEntity.ok(myself); - } - - private boolean usernameIsAlreadyTaken(String username) { - try { - userDAO.getByUsername(username); - return true; - } catch (NotFoundException e) { - return false; - } - } - - private boolean emailIsAlreadyTaken(String email) { - try { - userDAO.getByEmail(email); - return true; - } catch (NotFoundException e) { - return false; - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/common/Constants.java b/backend/src/main/java/de/learnlib/alex/common/Constants.java deleted file mode 100644 index f91c21e84..000000000 --- a/backend/src/main/java/de/learnlib/alex/common/Constants.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.common; - -import java.time.format.DateTimeFormatter; - -public class Constants { - - public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSxxx"); - - private Constants() { - throw new UnsupportedOperationException("The class cannot be instantiated."); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/common/exceptions/EntityLockedException.java b/backend/src/main/java/de/learnlib/alex/common/exceptions/EntityLockedException.java deleted file mode 100644 index 83eefeacd..000000000 --- a/backend/src/main/java/de/learnlib/alex/common/exceptions/EntityLockedException.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.common.exceptions; - -public class EntityLockedException extends RuntimeException { - - public EntityLockedException(String s) { - super(s); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/common/exceptions/ForbiddenOperationException.java b/backend/src/main/java/de/learnlib/alex/common/exceptions/ForbiddenOperationException.java deleted file mode 100644 index 61cf5e749..000000000 --- a/backend/src/main/java/de/learnlib/alex/common/exceptions/ForbiddenOperationException.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.common.exceptions; - -public class ForbiddenOperationException extends RuntimeException { - - public ForbiddenOperationException() { - } - - public ForbiddenOperationException(String message) { - super(message); - } - - public ForbiddenOperationException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/common/exceptions/LearnerInterruptedException.java b/backend/src/main/java/de/learnlib/alex/common/exceptions/LearnerInterruptedException.java deleted file mode 100644 index 598a00e91..000000000 --- a/backend/src/main/java/de/learnlib/alex/common/exceptions/LearnerInterruptedException.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.common.exceptions; - -/** Exception that is thrown if the user interrupts a learning process. */ -public class LearnerInterruptedException extends RuntimeException { - - /** - * Constructor. - * - * @param s - * The message. - */ - public LearnerInterruptedException(String s) { - super(s); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/common/exceptions/NotFoundException.java b/backend/src/main/java/de/learnlib/alex/common/exceptions/NotFoundException.java deleted file mode 100644 index f7a9216b4..000000000 --- a/backend/src/main/java/de/learnlib/alex/common/exceptions/NotFoundException.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.common.exceptions; - -/** - * An alternative to the default NotFoundException. - */ -public class NotFoundException extends RuntimeException { - - /** Constructor. */ - public NotFoundException() { - } - - /** - * Constructor. - * - * @param message - * The message of the exception. - */ - public NotFoundException(String message) { - super(message); - } - - /** - * Constructor. - * - * @param message - * The message of the exception. - * @param cause - * The cause of the exception. - */ - public NotFoundException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/common/exceptions/ResourcesExhaustedException.java b/backend/src/main/java/de/learnlib/alex/common/exceptions/ResourcesExhaustedException.java deleted file mode 100644 index 57a6ce425..000000000 --- a/backend/src/main/java/de/learnlib/alex/common/exceptions/ResourcesExhaustedException.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2015 - 2020 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.common.exceptions; - -public class ResourcesExhaustedException extends RuntimeException { - - public ResourcesExhaustedException(String s) { - super(s); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/common/exceptions/RestException.java b/backend/src/main/java/de/learnlib/alex/common/exceptions/RestException.java deleted file mode 100644 index 3692c7bcc..000000000 --- a/backend/src/main/java/de/learnlib/alex/common/exceptions/RestException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.common.exceptions; - -import org.springframework.http.HttpStatus; - -public class RestException extends RuntimeException { - - private HttpStatus status; - - public RestException(HttpStatus status, String message) { - super(message); - this.status = status; - } - - public HttpStatus getStatus() { - return status; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/common/exceptions/RestExceptionHandler.java b/backend/src/main/java/de/learnlib/alex/common/exceptions/RestExceptionHandler.java deleted file mode 100644 index d443a76e4..000000000 --- a/backend/src/main/java/de/learnlib/alex/common/exceptions/RestExceptionHandler.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.common.exceptions; - -import de.learnlib.alex.common.utils.RestError; -import de.learnlib.alex.learning.exceptions.LearnerException; -import java.util.List; -import java.util.stream.Collectors; -import javax.persistence.EntityNotFoundException; -import javax.validation.ConstraintViolationException; -import javax.validation.ValidationException; -import javax.ws.rs.InternalServerErrorException; -import org.apache.shiro.authz.UnauthorizedException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.NestedExceptionUtils; -import org.springframework.core.annotation.Order; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.transaction.TransactionSystemException; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; - -/** - * ExceptionMapper that will catch all {@link DataIntegrityViolationException}s thrown by the REST resources. - */ -@Order -@ControllerAdvice -public class RestExceptionHandler extends ResponseEntityExceptionHandler { - - private static final Logger logger = LoggerFactory.getLogger(RestExceptionHandler.class); - - @ExceptionHandler(DataIntegrityViolationException.class) - protected ResponseEntity handleDataIntegrityViolation(DataIntegrityViolationException e) { - logger.info("DataIntegrityViolationException caught.", e); - final RestError error = new RestError(HttpStatus.INTERNAL_SERVER_ERROR, e); - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error); - } - - @ExceptionHandler(LearnerException.class) - protected ResponseEntity handleLearnerException(LearnerException e) { - logger.info("LearnerException caught.", e); - final RestError error = new RestError(HttpStatus.BAD_REQUEST, e); - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error); - } - - @ExceptionHandler(ForbiddenOperationException.class) - protected ResponseEntity handleForbiddenOperationException(ForbiddenOperationException e) { - logger.info("ForbiddenOperationException caught.", e); - final RestError error = new RestError(HttpStatus.FORBIDDEN, e); - return ResponseEntity.status(HttpStatus.FORBIDDEN).body(error); - } - - @ExceptionHandler(NotFoundException.class) - protected ResponseEntity handleNotFoundException(NotFoundException e) { - logger.info("NotFoundException caught.", e); - final RestError error = new RestError(HttpStatus.NOT_FOUND, e); - return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error); - } - - @ExceptionHandler(EntityNotFoundException.class) - protected ResponseEntity handleEntityNotFoundException(EntityNotFoundException e) { - logger.info("EntityNotFoundException caught.", e); - final RestError error = new RestError(HttpStatus.NOT_FOUND, e); - return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error); - } - - @ExceptionHandler(TransactionSystemException.class) - protected ResponseEntity handleTransactionSystemException(TransactionSystemException e) { - logger.info("TransactionSystemException caught.", e); - - String message; - final Throwable rootCause = NestedExceptionUtils.getRootCause(e); - if (rootCause instanceof ConstraintViolationException) { - final List messages = ((ConstraintViolationException) rootCause).getConstraintViolations().stream() - .map(violation -> violation.getPropertyPath() + ": " + violation.getMessage()) - .collect(Collectors.toList()); - message = String.join(",", messages); - } else { - message = e.getMessage(); - } - - final RestError error = new RestError(HttpStatus.BAD_REQUEST, new Exception(message)); - return ResponseEntity.badRequest().body(error); - } - - @ExceptionHandler(UnauthorizedException.class) - protected ResponseEntity handleUnauthorizedException(UnauthorizedException e) { - logger.info("UnauthorizedException caught.", e); - final RestError error = new RestError(HttpStatus.UNAUTHORIZED, e); - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(error); - } - - @ExceptionHandler(InternalServerErrorException.class) - protected ResponseEntity handleInternalServerErrorException(InternalServerErrorException e) { - logger.info("InternalServerErrorException caught.", e); - final RestError error = new RestError(HttpStatus.INTERNAL_SERVER_ERROR, e); - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error); - } - - @ExceptionHandler(ValidationException.class) - protected ResponseEntity handleValidationException(ValidationException e) { - logger.info("ValidationException caught.", e); - final RestError error = new RestError(HttpStatus.BAD_REQUEST, e); - return ResponseEntity.badRequest().body(error); - } - - @ExceptionHandler(IllegalArgumentException.class) - protected ResponseEntity handleIllegalArgumentException(IllegalArgumentException e) { - logger.info("IllegalArgumentException caught.", e); - final RestError error = new RestError(HttpStatus.BAD_REQUEST, e); - return ResponseEntity.badRequest().body(error); - } - - @ExceptionHandler(EntityLockedException.class) - protected ResponseEntity handleEntityLockedException(EntityLockedException e) { - logger.info("EntityLockedException caught.", e); - final RestError error = new RestError(HttpStatus.LOCKED, e); - return ResponseEntity.status(HttpStatus.LOCKED).body(error); - } - - @ExceptionHandler(ResourcesExhaustedException.class) - protected ResponseEntity handleResourcesExhaustedException(ResourcesExhaustedException e) { - logger.info("ResourcesExhaustedException.java caught.", e); - final RestError error = new RestError(HttpStatus.LOCKED, e); - return ResponseEntity.status(HttpStatus.LOCKED).body(error); - } - - @ExceptionHandler(RestException.class) - protected ResponseEntity handleRestException(RestException e) { - logger.info("RestException.java caught.", e); - final var error = new RestError(e.getStatus(), e); - return ResponseEntity.status(e.getStatus()).body(error); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/common/utils/CSSUtils.java b/backend/src/main/java/de/learnlib/alex/common/utils/CSSUtils.java deleted file mode 100644 index 65bc8e2d5..000000000 --- a/backend/src/main/java/de/learnlib/alex/common/utils/CSSUtils.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.common.utils; - -/** - * Utility class for CSS stuff. - */ -public final class CSSUtils { - - /** ASCII Code for the unit separator character, which is not really printable. */ - private static final int UNIT_SEPARATOR_CHARACTER = 31; - - /** ASCII Code for the delete character, which is not really printable. */ - private static final int DELETE_CHARACTER = 127; - - /** - * Deactivate the constructor because this is a utility class. - */ - private CSSUtils() { - } - - /** - * Escape special characters in css id selectors. - * Port of https://github.com/mathiasbynens/CSS.escape/blob/master/css.escape.js - * - * @param id - * The id selector of an element starting with # - * @return The escaped id - */ - private static String escapeIdentifier(String id) { - StringBuilder result = new StringBuilder(); - char firstUnit = id.charAt(0); - - for (int i = 0; i < id.length(); i++) { - char unit = id.charAt(i); - - if (unit == 0) { // null character - return null; - } - - if ( - unit <= UNIT_SEPARATOR_CHARACTER || unit == DELETE_CHARACTER // the non printable ASCII characters - || (i == 0 && unit >= '0' && unit <= '9') - || (i == 1 && unit >= '0' && unit <= '9' && firstUnit == '-') - ) { - result.append("\\").append(Integer.toHexString(unit)).append(" "); - continue; - } - - if ( - unit > DELETE_CHARACTER // "second half" of the (extended) ASCII table - || unit == '-' - || unit == '_' - || unit >= '0' && unit <= '9' - || unit >= 'A' && unit <= 'Z' - || unit >= 'a' && unit <= 'z' - ) { - result.append(unit); - continue; - } - - result.append("\\").append(unit); - } - - return result.toString(); - } - - /** - * Escapes special characters in CSS selectors in case it contains ids. - * - * @param css - * The css string to escape - * @return The escaped css string - */ - public static String escapeSelector(String css) { - - if (!css.contains(" ") && css.startsWith("#")) { - return "#" + escapeIdentifier(css.substring(1)); - } else { - StringBuilder result = new StringBuilder(); - String[] pieces = css.split(" "); - - for (String p : pieces) { - if (p.startsWith("#")) { - result.append("#").append(escapeIdentifier(p.substring(1))).append(" "); - } else { - result.append(p).append(" "); - } - } - - return result.toString().trim(); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/common/utils/JSONHelpers.java b/backend/src/main/java/de/learnlib/alex/common/utils/JSONHelpers.java deleted file mode 100644 index 99bf584b3..000000000 --- a/backend/src/main/java/de/learnlib/alex/common/utils/JSONHelpers.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.common.utils; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.jayway.jsonpath.InvalidJsonException; -import com.jayway.jsonpath.InvalidPathException; -import com.jayway.jsonpath.JsonPath; -import de.learnlib.alex.data.entities.actions.rest.CheckAttributeTypeAction.JsonType; -import java.util.LinkedHashMap; -import net.minidev.json.JSONArray; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Helper class for some JSON stuff. - */ -public final class JSONHelpers { - - private static final Logger logger = LoggerFactory.getLogger(JSONHelpers.class); - - private static final ObjectMapper objectMapper = new ObjectMapper(); - - /** - * Disabled default constructor, this is only a utility class with static methods. - */ - private JSONHelpers() { - } - - /** - * Get the value of an attribute from a JSON encoded String. - * - * @param json - * The JSON with the the attribute. - * @param attribute - * The attribute to search for. - * @return The value of the attribute as JSON encoded String or null. - */ - public static String getAttributeValue(String json, String attribute) { - try { - Object object = JsonPath.parse(json).read(attribute); - if (object instanceof LinkedHashMap) { - return objectMapper.writeValueAsString(object); - } else { - return object.toString(); - } - } catch (InvalidJsonException | JsonProcessingException e) { - logger.info("JSON was not valid, e.g. the body was empty.", e); - return null; - } catch (InvalidPathException e) { - logger.info("Could not parse the JSON to get the value of an attribute.", e); - return null; - } catch (IllegalArgumentException e) { - logger.info("Wrong arguments passed.", e); - return null; - } - } - - /** - * Get the type of an attribute from a JSON encoded String. - * - * @param json - * The JSON with the the attribute. - * @param attribute - * The attribute to search for. - * @return The type of the attribute or null. - */ - public static JsonType getAttributeType(String json, String attribute) { - try { - Object o = JsonPath.read(json, attribute); - if (o == null) { - return JsonType.NULL; - } else if (o instanceof String) { - return JsonType.STRING; - } else if (o instanceof Integer || o instanceof Double) { - return JsonType.INTEGER; - } else if (o instanceof JSONArray) { - return JsonType.ARRAY; - } else if (o instanceof LinkedHashMap) { - return JsonType.OBJECT; - } else if (o instanceof Boolean) { - return JsonType.BOOLEAN; - } else { - logger.info("Unsupported JSON type."); - return null; - } - } catch (InvalidJsonException e) { - logger.info("JSON was not valid, e.g. the body was empty.", e); - return null; - } catch (InvalidPathException e) { - logger.info("Could not parse the JSON to get the type of an attribute.", e); - return null; - } catch (IllegalArgumentException e) { - logger.info("Wrong arguments passed.", e); - return null; - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/common/utils/LoggerMarkers.java b/backend/src/main/java/de/learnlib/alex/common/utils/LoggerMarkers.java deleted file mode 100644 index 1ad18adc0..000000000 --- a/backend/src/main/java/de/learnlib/alex/common/utils/LoggerMarkers.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.common.utils; - -import org.slf4j.Marker; -import org.slf4j.MarkerFactory; - -/** Markers for logging. */ -public final class LoggerMarkers { - - /** Marker for learning processes. */ - public static final Marker LEARNER = MarkerFactory.getMarker("LEARNER"); - - private LoggerMarkers() { - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/common/utils/RestError.java b/backend/src/main/java/de/learnlib/alex/common/utils/RestError.java deleted file mode 100644 index 93f2a8732..000000000 --- a/backend/src/main/java/de/learnlib/alex/common/utils/RestError.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.common.utils; - -import com.fasterxml.jackson.annotation.JsonGetter; -import org.springframework.http.HttpStatus; - -/** - * Entity class for the JSON error messages. - */ -public class RestError { - - /** - * Status of the error. - */ - private final HttpStatus status; - - /** - * The cause of the error. - */ - private final Exception exception; - - /** - * Constructor. - * - * @param status - * The status of the error. - * @param exception - * The exception that caused the error, could be null. - */ - public RestError(HttpStatus status, Exception exception) { - this.status = status; - this.exception = exception; - } - - /** - * Returns the proper status code for this error. - * - * @return The HTTP status code. - */ - @JsonGetter - public int getStatusCode() { - return status.value(); - } - - /** - * Returns a short description of the status (like the short HTTP error messages). - * - * @return A short string to describe the status. - */ - @JsonGetter - public String getStatusText() { - return status.getReasonPhrase(); - } - - /** - * Get the message of the exception that cause this error. - * - * @return The message of the error. - */ - @JsonGetter - public String getMessage() { - if (exception != null) { - return exception.getMessage(); - } else { - return ""; - } - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/common/utils/SearchHelper.java b/backend/src/main/java/de/learnlib/alex/common/utils/SearchHelper.java deleted file mode 100644 index 4aa9b92e2..000000000 --- a/backend/src/main/java/de/learnlib/alex/common/utils/SearchHelper.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.common.utils; - -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.CounterStoreConnector; -import de.learnlib.alex.learning.services.connectors.FileStoreConnector; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Helper class to make searching in a text easier. - */ -public final class SearchHelper { - - /** - * Disabled default constructor, this is only a utility class with static methods. - */ - private SearchHelper() { - } - - /** - * Search for a value within a text. If you use a regular expression, this method allows to use the '.' for line - * breaks. - * - * @param value - * The value to search. This can be a regular expression. - * @param text - * The text to match. - * @param regex - * Flag if the value is a regular expression or not. - * @return true on success, False otherwise. - */ - public static boolean search(String value, String text, boolean regex) { - if (regex) { - return searchWithRegex(value, text); - } else { - return searchWithoutRegex(value, text); - } - } - - private static boolean searchWithoutRegex(String value, String text) { - return text.contains(value); - } - - /** - * Search for a regular expression within a text. This method allows to use the '.' for line breaks. - * - * @param regex - * The pattern to search. - * @param text - * The text to match. - * @return true on success, false otherwise. - */ - public static boolean searchWithRegex(String regex, String text) { - Pattern pattern = Pattern.compile(regex, Pattern.DOTALL); - Matcher matcher = pattern.matcher(text); - return matcher.find(); - } - - /** - * Replace all counters and variables within an input string by their actual values. - * - * @param connector - * The connectors to connect to the counter and variable stores. - * @param projectId - * The project as context. - * @param text - * The input string to pares and to replace the counters and variables in. - * @return The input string with all counter adn variables replaced by their values. - * @throws IllegalStateException - * If a variable value should be inserted, but the variable does not exists or was never set. - */ - public static String insertVariableValues(ConnectorManager connector, Long projectId, String text) - throws IllegalStateException { - - final VariableStoreConnector variableStore = connector.getConnector(VariableStoreConnector.class); - final CounterStoreConnector counterStore = connector.getConnector(CounterStoreConnector.class); - final FileStoreConnector fileStore = connector.getConnector(FileStoreConnector.class); - - String result = "" + text; - - final Pattern pattern = Pattern.compile("\\{\\{(\\$|\\#|\\\\|:)(.*?)}}"); - final Matcher matcher = pattern.matcher(result); - - while (matcher.find()) { - final String type = matcher.group(1); - final String name = matcher.group(2); - - switch (type) { - case "$": - result = result.replaceAll("\\{\\{\\$" + name + "}}", Matcher.quoteReplacement(variableStore.get(name))); - break; - case "#": - result = result.replaceAll("\\{\\{\\#" + name + "}}", String.valueOf(counterStore.get(name))); - break; - case "\\": - final String path = fileStore.getAbsoluteFileLocation(projectId, name); - result = result.replaceAll("\\{\\{\\\\" + name + "}}", path); - break; - case ":": - final String value = connector.getEnvironment().getVariablesAsMap().get(name); - result = result.replaceAll("\\{\\{:" + name + "}}", value); - break; - default: - break; - } - } - - return result; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/dao/CounterDAO.java b/backend/src/main/java/de/learnlib/alex/data/dao/CounterDAO.java deleted file mode 100644 index 994af72b2..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/dao/CounterDAO.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.dao; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.entities.Counter; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.repositories.CounterRepository; -import de.learnlib.alex.data.repositories.ProjectRepository; -import java.util.List; -import javax.validation.ValidationException; -import org.apache.shiro.authz.UnauthorizedException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -/** - * Implementation of a CounterDAO using Hibernate. - */ -@Service -@Transactional(rollbackFor = Exception.class) -public class CounterDAO { - - private final ProjectDAO projectDAO; - private final ProjectRepository projectRepository; - private final CounterRepository counterRepository; - - @Autowired - public CounterDAO(ProjectDAO projectDAO, - CounterRepository counterRepository, - ProjectRepository projectRepository - ) { - this.projectDAO = projectDAO; - this.counterRepository = counterRepository; - this.projectRepository = projectRepository; - } - - public Counter create(User user, Long projectId, Counter counter) { - final Project project = projectRepository.getOne(projectId); - projectDAO.checkAccess(user, project); - - checkNameDoesNotExistInProject(project.getId(), counter.getName()); - - final var c = new Counter(); - c.setName(counter.getName()); - c.setValue(counter.getValue()); - c.setProject(project); - - return counterRepository.save(c); - } - - public void create(User user, Counter counter) { - final Project project = projectRepository.findById(counter.getProjectId()).orElse(null); - projectDAO.checkAccess(user, project); - - checkNameDoesNotExistInProject(project.getId(), counter.getName()); - - counter.setId(null); - counter.setProject(project); - counterRepository.save(counter); - } - - public List getAll(User user, Long projectId) { - final Project project = projectRepository.findById(projectId).orElse(null); - projectDAO.checkAccess(user, project); - return counterRepository.findAllByProject(project); - } - - public Counter update(User user, Long projectId, Long counterId, Counter counter) { - final var project = projectRepository.getOne(projectId); - final var counterToUpdate = counterRepository.getOne(counterId); - checkAccess(user, project, counterToUpdate); - - counterToUpdate.setValue(counter.getValue()); - - return counterRepository.save(counterToUpdate); - } - - public Counter update(User user, Counter counter) { - final Counter counterIdDb = doGet(user, counter.getProjectId(), counter.getId()); - - if (!counterIdDb.getName().equals(counter.getName())) { - throw new ValidationException("counters cannot be renamed"); - } - - counterIdDb.setValue(counter.getValue()); - return counterRepository.save(counterIdDb); - } - - public void delete(User user, Long projectId, List counterIds) { - final Project project = projectRepository.findById(projectId).orElse(null); - final List counters = counterRepository.findAllByIdIn(counterIds); - - if (counters.size() != counterIds.size()) { - throw new NotFoundException("At least one counter cannot be found"); - } - - for (Counter counter : counters) { - checkAccess(user, project, counter); - } - counterRepository.deleteAll(counters); - } - - public void checkAccess(User user, Project project, Counter counter) { - projectDAO.checkAccess(user, project); - - if (counter == null) { - throw new NotFoundException("The counter could not be found."); - } - - if (!counter.getProjectId().equals(project.getId())) { - throw new UnauthorizedException("You are not allowed to access the counter."); - } - } - - private Counter doGet(User user, Long projectId, Long counterId) { - final Project project = projectRepository.findById(projectId).orElse(null); - final Counter counter = counterRepository.findById(counterId).orElse(null); - checkAccess(user, project, counter); - return counter; - } - - private void checkNameDoesNotExistInProject(Long projectId, String name) { - if (counterRepository.findByProject_IdAndName(projectId, name) != null) { - throw new ValidationException("A counter with the name already exists."); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/dao/FileDAO.java b/backend/src/main/java/de/learnlib/alex/data/dao/FileDAO.java deleted file mode 100644 index 9d643d09e..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/dao/FileDAO.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.dao; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.UploadableFile; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.data.repositories.UploadableFileRepository; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; -import javax.annotation.PostConstruct; -import org.apache.commons.io.FileUtils; -import org.apache.shiro.authz.UnauthorizedException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.multipart.MultipartFile; - -/** - * Simple implementation of a FileDAO. - */ -@Service -@Transactional(rollbackFor = Exception.class) -public class FileDAO { - - /** The size of the output write buffer in bytes. */ - public static final int WRITE_BUFFER_SIZE = 1024; - - private final ProjectDAO projectDAO; - private final UploadableFileRepository fileRepository; - private final ProjectRepository projectRepository; - - /** - * The path of the upload directory as String. This will be injected by Spring and is configured in the - * applications.properties file. - */ - @Value("${alex.filesRootDir}") - private String filesRootDir; - - /** - * Constructor. - * - * @param projectDAO - * The injected project DAO to use. - * @param fileRepository - * The injected file repository. - */ - @Autowired - public FileDAO(ProjectDAO projectDAO, UploadableFileRepository fileRepository, ProjectRepository projectRepository) { - this.projectDAO = projectDAO; - this.fileRepository = fileRepository; - this.projectRepository = projectRepository; - } - - /** - * Create the uploads directory, if necessary. Called by Spring after the DAO object is created and all injections - * are present. - */ - @PostConstruct - private void init() { - File uploadBaseDirectory = Paths.get(filesRootDir, "users").toFile(); - if (!uploadBaseDirectory.exists()) { - uploadBaseDirectory.mkdirs(); - } - } - - public UploadableFile create(User user, Long projectId, MultipartFile file) - throws IllegalStateException, IOException { - final Project project = projectDAO.getByID(user, projectId); // access check - - Path uploadedDirectoryLocation = Paths.get(getUploadsDir(user, projectId)); - - File uploadDirectory = uploadedDirectoryLocation.toFile(); - if (!uploadDirectory.exists()) { - uploadDirectory.mkdirs(); - } - - if (!uploadDirectory.isDirectory()) { - throw new IllegalStateException("Could not find the right directory to upload the file."); - } - - Path uploadedFileLocation = Paths.get(uploadedDirectoryLocation.toString(), - file.getOriginalFilename()); - - if (uploadedFileLocation.toFile().exists()) { - throw new IllegalStateException("The file already exists."); - } - - writeToFile(file.getInputStream(), uploadedFileLocation.toString()); - - final UploadableFile uf = new UploadableFile(); - uf.setProject(project); - uf.setName(file.getOriginalFilename()); - return fileRepository.save(uf); - } - - public List getAll(User user, Long projectId) { - projectDAO.getByID(user, projectId); // access check - - final List files = fileRepository.findAllByProject_Id(projectId); - return files; - } - - public File getFile(User user, Long projectId, Long fileId) { - return getFileInternal(user, projectId, fileId); - } - - public File getFileByName(User user, Long projectId, String filename) { - final UploadableFile uf = fileRepository.findByProject_IdAndName(projectId, filename); - return getFileInternal(user, projectId, uf.getId()); - } - - public void delete(User user, Long projectId, Long fileId) { - final File file = getFileInternal(user, projectId, fileId); - file.delete(); - fileRepository.deleteById(fileId); - } - - public void delete(User user, Long projectId, List fileIds) { - final Project project = projectRepository.findById(projectId).orElse(null); - final List files = fileRepository.findAllByIdIn(fileIds); - - for (UploadableFile f : files) { - checkAccess(user, project, f); - } - - for (UploadableFile f : files) { - final File fileToDelete = getFileInternal(user, project, f); - fileToDelete.delete(); - fileRepository.deleteById(f.getId()); - } - } - - private File getFileInternal(User user, Long projectId, Long fileId) { - final Project project = projectRepository.findById(projectId).orElse(null); - final UploadableFile uf = fileRepository.findById(fileId).orElse(null); - return getFileInternal(user, project, uf); - } - - private File getFileInternal(User user, Project project, UploadableFile file) { - checkAccess(user, project, file); - - final File uploadDirectory = getUploadDirectory(user, project.getId()); - final Path uploadedFileLocation = Paths.get(uploadDirectory.getPath(), file.getName()); - final File f = uploadedFileLocation.toFile(); - - if (!f.exists()) { - throw new NotFoundException("Could not find the file in the project."); - } - - return f; - } - - public void deleteProjectDirectory(User user, Long projectId) throws IOException { - File dir = Paths.get(getProjectDir(user, projectId)).toFile(); - if (dir.exists()) { - FileUtils.deleteDirectory(dir); - fileRepository.deleteAllByProject_Id(projectId); - } - } - - public void deleteUserDirectory(User user) throws IOException { - File dir = Paths.get(getUserDir(user)).toFile(); - if (dir.exists()) { - FileUtils.deleteDirectory(dir); - } - } - - private File getUploadDirectory(User user, Long projectId) { - Path uploadedDirectoryLocation = Paths.get(getUploadsDir(user, projectId)); - File uploadDirectory = uploadedDirectoryLocation.toFile(); - - if (!uploadDirectory.exists() || !uploadDirectory.isDirectory()) { - try { - uploadDirectory.mkdirs(); - } catch (SecurityException e) { - throw new NotFoundException("Could not find the project directory you are looking for."); - } - } - - return uploadDirectory; - } - - // save uploaded file to new location - private void writeToFile(InputStream uploadedInputStream, String uploadedFileLocation) - throws IOException { - try (OutputStream out = new FileOutputStream(new File(uploadedFileLocation))) { - int read; - byte[] bytes = new byte[WRITE_BUFFER_SIZE]; - - while ((read = uploadedInputStream.read(bytes)) != -1) { - out.write(bytes, 0, read); - } - out.flush(); - } - } - - private String getUserDir(User user) { - return Paths.get(filesRootDir, "users", String.valueOf(user.getId())).toString(); - } - - private String getProjectDir(User user, Long projectId) { - return Paths.get(getUserDir(user), "projects", String.valueOf(projectId)).toString(); - } - - private String getUploadsDir(User user, Long projectId) { - return Paths.get(getProjectDir(user, projectId), "uploads").toString(); - } - - private void checkAccess(User user, Project project, UploadableFile file) { - projectDAO.checkAccess(user, project); - - if (file == null) { - throw new NotFoundException("The file could not be found."); - } - - if (!project.equals(file.getProject())) { - throw new UnauthorizedException("You may not access the file."); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/dao/ParameterizedSymbolDAO.java b/backend/src/main/java/de/learnlib/alex/data/dao/ParameterizedSymbolDAO.java deleted file mode 100644 index aa78f9e1f..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/dao/ParameterizedSymbolDAO.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.dao; - -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolOutputMapping; -import de.learnlib.alex.data.repositories.ParameterizedSymbolRepository; -import de.learnlib.alex.data.repositories.SymbolOutputMappingRepository; -import de.learnlib.alex.data.repositories.SymbolParameterValueRepository; -import de.learnlib.alex.data.repositories.SymbolRepository; -import java.util.stream.Collectors; -import org.hibernate.Hibernate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -/** - * The implementation of the {@link ParameterizedSymbolDAO}. - */ -@Service -@Transactional(rollbackFor = Exception.class) -public class ParameterizedSymbolDAO { - - private final SymbolRepository symbolRepository; - private final SymbolParameterValueRepository symbolParameterValueRepository; - private final ParameterizedSymbolRepository parameterizedSymbolRepository; - private final SymbolOutputMappingRepository symbolOutputMappingRepository; - - @Autowired - public ParameterizedSymbolDAO( - SymbolRepository symbolRepository, - SymbolParameterValueRepository symbolParameterValueRepository, - ParameterizedSymbolRepository parameterizedSymbolRepository, - SymbolOutputMappingRepository symbolOutputMappingRepository) { - this.symbolRepository = symbolRepository; - this.symbolParameterValueRepository = symbolParameterValueRepository; - this.parameterizedSymbolRepository = parameterizedSymbolRepository; - this.symbolOutputMappingRepository = symbolOutputMappingRepository; - } - - public ParameterizedSymbol create(ParameterizedSymbol pSymbol) { - final Symbol symbol = symbolRepository.findById(pSymbol.getSymbol().getId()).orElse(null); - pSymbol.setSymbol(symbol); - pSymbol.setParameterValues(symbolParameterValueRepository.saveAll(pSymbol.getParameterValues())); - - if (pSymbol.getOutputMappings().size() != pSymbol.getSymbol().getOutputs().size()) { - pSymbol.setOutputMappings(pSymbol.getSymbol().getOutputs().stream().map(out -> { - final SymbolOutputMapping mapping = new SymbolOutputMapping(); - mapping.setParameter(out); - mapping.setName(out.getName()); - return mapping; - }).collect(Collectors.toList())); - } - - pSymbol.setOutputMappings(symbolOutputMappingRepository.saveAll(pSymbol.getOutputMappings())); - return parameterizedSymbolRepository.save(pSymbol); - } - - public void delete(ParameterizedSymbol pSymbol) { - parameterizedSymbolRepository.delete(pSymbol); - } - - public static void loadLazyRelations(ParameterizedSymbol pSymbol) { - Hibernate.initialize(pSymbol.getParameterValues()); - Hibernate.initialize(pSymbol.getOutputMappings()); - SymbolDAO.loadLazyRelations(pSymbol.getSymbol()); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/dao/ProjectDAO.java b/backend/src/main/java/de/learnlib/alex/data/dao/ProjectDAO.java deleted file mode 100644 index 590c0a51a..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/dao/ProjectDAO.java +++ /dev/null @@ -1,578 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.dao; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.auth.dao.UserDAO; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.auth.entities.UserRole; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.entities.CreateProjectForm; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.data.entities.ProjectEnvironmentVariable; -import de.learnlib.alex.data.entities.ProjectUrl; -import de.learnlib.alex.data.entities.SymbolGroup; -import de.learnlib.alex.data.entities.export.ProjectExportableEntity; -import de.learnlib.alex.data.repositories.ParameterizedSymbolRepository; -import de.learnlib.alex.data.repositories.ProjectEnvironmentRepository; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.data.repositories.ProjectUrlRepository; -import de.learnlib.alex.data.repositories.SymbolActionRepository; -import de.learnlib.alex.data.repositories.SymbolParameterRepository; -import de.learnlib.alex.data.repositories.SymbolStepRepository; -import de.learnlib.alex.data.repositories.UploadableFileRepository; -import de.learnlib.alex.learning.dao.LearnerSetupDAO; -import de.learnlib.alex.learning.entities.LearnerSetup; -import de.learnlib.alex.learning.repositories.LearnerResultRepository; -import de.learnlib.alex.learning.repositories.LearnerResultStepRepository; -import de.learnlib.alex.learning.repositories.LearnerSetupRepository; -import de.learnlib.alex.modelchecking.dao.LtsFormulaDAO; -import de.learnlib.alex.modelchecking.dao.LtsFormulaSuiteDAO; -import de.learnlib.alex.modelchecking.entities.LtsFormula; -import de.learnlib.alex.modelchecking.entities.LtsFormulaSuite; -import de.learnlib.alex.testing.dao.TestDAO; -import de.learnlib.alex.testing.dao.TestExecutionConfigDAO; -import de.learnlib.alex.testing.dao.TestReportDAO; -import de.learnlib.alex.testing.entities.Test; -import de.learnlib.alex.testing.entities.TestExecutionConfig; -import de.learnlib.alex.testing.entities.TestSuite; -import de.learnlib.alex.testing.repositories.TestExecutionConfigRepository; -import de.learnlib.alex.testing.repositories.TestReportRepository; -import de.learnlib.alex.testing.repositories.TestRepository; -import de.learnlib.alex.websocket.services.ProjectPresenceService; -import de.learnlib.alex.websocket.services.SymbolPresenceService; -import de.learnlib.alex.websocket.services.TestPresenceService; -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import javax.validation.ValidationException; -import org.apache.shiro.authz.UnauthorizedException; -import org.hibernate.Hibernate; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -/** - * Implementation of a ProjectDAO using Spring Data. - */ -@Service -@Transactional(rollbackFor = Exception.class) -public class ProjectDAO { - - private static final Logger logger = LoggerFactory.getLogger(ProjectDAO.class); - - private final ProjectRepository projectRepository; - private final LearnerResultRepository learnerResultRepository; - private final TestReportRepository testReportRepository; - private final ParameterizedSymbolRepository parameterizedSymbolRepository; - private final SymbolStepRepository symbolStepRepository; - private final SymbolActionRepository symbolActionRepository; - private final FileDAO fileDAO; - private final ProjectEnvironmentDAO projectEnvironmentDAO; - private final ProjectUrlRepository projectUrlRepository; - private final TestExecutionConfigRepository testExecutionConfigRepository; - private final ProjectEnvironmentRepository environmentRepository; - private final SymbolGroupDAO symbolGroupDAO; - private final TestDAO testDAO; - private final UserDAO userDAO; - private final TestRepository testRepository; - private final SymbolParameterRepository symbolParameterRepository; - private final UploadableFileRepository uploadableFileRepository; - private final LearnerSetupRepository learnerSetupRepository; - private final TestPresenceService testPresenceService; - private final SymbolPresenceService symbolPresenceService; - private final ProjectPresenceService projectPresenceService; - private final TestReportDAO testReportDAO; - private final LtsFormulaSuiteDAO ltsFormulaSuiteDAO; - private final LtsFormulaDAO ltsFormulaDAO; - private final LearnerResultStepRepository learnerResultStepRepository; - private final LearnerSetupDAO learnerSetupDAO; - private final TestExecutionConfigDAO testExecutionConfigDAO; - - @Autowired - public ProjectDAO(ProjectRepository projectRepository, - LearnerResultRepository learnerResultRepository, - TestReportRepository testReportRepository, - @Lazy FileDAO fileDAO, - ParameterizedSymbolRepository parameterizedSymbolRepository, - SymbolStepRepository symbolStepRepository, - SymbolActionRepository symbolActionRepository, - @Lazy ProjectEnvironmentDAO projectEnvironmentDAO, - ProjectUrlRepository projectUrlRepository, - TestExecutionConfigRepository testExecutionConfigRepository, - @Lazy TestDAO testDAO, - @Lazy UserDAO userDAO, - ProjectEnvironmentRepository environmentRepository, - @Lazy SymbolGroupDAO symbolGroupDAO, - TestRepository testRepository, - SymbolParameterRepository symbolParameterRepository, - UploadableFileRepository uploadableFileRepository, - LearnerSetupRepository learnerSetupRepository, - LearnerResultStepRepository learnerResultStepRepository, - @Lazy TestPresenceService testPresenceService, - @Lazy SymbolPresenceService symbolPresenceService, - @Lazy ProjectPresenceService projectPresenceService, - @Lazy TestReportDAO testReportDAO, - @Lazy LtsFormulaSuiteDAO ltsFormulaSuiteDAO, - @Lazy LtsFormulaDAO ltsFormulaDAO, - @Lazy LearnerSetupDAO learnerSetupDAO, - @Lazy TestExecutionConfigDAO testExecutionConfigDAO) { - this.projectRepository = projectRepository; - this.learnerResultRepository = learnerResultRepository; - this.fileDAO = fileDAO; - this.testReportRepository = testReportRepository; - this.parameterizedSymbolRepository = parameterizedSymbolRepository; - this.symbolStepRepository = symbolStepRepository; - this.symbolActionRepository = symbolActionRepository; - this.projectEnvironmentDAO = projectEnvironmentDAO; - this.projectUrlRepository = projectUrlRepository; - this.testExecutionConfigRepository = testExecutionConfigRepository; - this.environmentRepository = environmentRepository; - this.symbolGroupDAO = symbolGroupDAO; - this.testDAO = testDAO; - this.testRepository = testRepository; - this.symbolParameterRepository = symbolParameterRepository; - this.uploadableFileRepository = uploadableFileRepository; - this.userDAO = userDAO; - this.learnerSetupRepository = learnerSetupRepository; - this.testPresenceService = testPresenceService; - this.symbolPresenceService = symbolPresenceService; - this.projectPresenceService = projectPresenceService; - this.testReportDAO = testReportDAO; - this.ltsFormulaSuiteDAO = ltsFormulaSuiteDAO; - this.ltsFormulaDAO = ltsFormulaDAO; - this.learnerResultStepRepository = learnerResultStepRepository; - this.learnerSetupDAO = learnerSetupDAO; - this.testExecutionConfigDAO = testExecutionConfigDAO; - } - - public Project create(final User user, final CreateProjectForm projectForm) { - final Project project = new Project(); - project.addOwner(user); - project.setName(projectForm.getName()); - project.setDescription(projectForm.getDescription()); - - final SymbolGroup defaultGroup = new SymbolGroup(); - defaultGroup.setName("Default group"); - defaultGroup.setProject(project); - project.addGroup(defaultGroup); - - final TestSuite testSuite = new TestSuite(); - testSuite.setName("Root"); - testSuite.setProject(project); - project.getTests().add(testSuite); - - final Project createdProject = projectRepository.save(project); - - final ProjectEnvironment defaultEnv = new ProjectEnvironment(); - defaultEnv.setName("Production"); - defaultEnv.setDefault(true); - final var createdDefaultEnvironment = projectEnvironmentDAO.create(user, createdProject.getId(), defaultEnv); - - final ProjectUrl projectUrl = new ProjectUrl(); - projectUrl.setUrl(projectForm.getUrl()); - projectUrl.setEnvironment(createdDefaultEnvironment); - projectUrl.setName("Base"); - projectUrl.setDefault(true); - final ProjectUrl createdProjectUrl = projectUrlRepository.save(projectUrl); - createdDefaultEnvironment.getUrls().add(createdProjectUrl); - projectEnvironmentDAO.update( - user, - createdProject.getId(), - createdDefaultEnvironment.getId(), - createdDefaultEnvironment - ); - - return loadLazyRelations(createdProject); - } - - public List getAll(User user) { - List projects = projectRepository.findAllByUser_Id(user.getId()); - projects.forEach(this::loadLazyRelations); - return projects; - } - - public Project getByID(User user, Long projectId) { - final Project project = projectRepository.findById(projectId).orElse(null); - checkAccess(user, project); - loadLazyRelations(project); - return project; - } - - public Project update(User user, Long projectId, Project project) { - final Project projectInDb = projectRepository.findById(projectId).orElse(null); - checkAccess(user, projectInDb); - - if (!projectInDb.getOwners().contains(user) && user.getRole() != UserRole.ADMIN) { - throw new UnauthorizedException("You are not allowed to update this project."); - } - - projectInDb.setName(project.getName()); - projectInDb.setDescription(project.getDescription()); - - final Project updatedProject = projectRepository.save(projectInDb); - loadLazyRelations(updatedProject); - - return updatedProject; - } - - public void delete(User user, Long projectId) { - final Project project = projectRepository.findById(projectId).orElse(null); - checkAccess(user, project); - - if (!project.getOwners().contains(user) && user.getRole() != UserRole.ADMIN) { - throw new UnauthorizedException("You are not allowed to delete this project."); - } - - symbolActionRepository.deleteAllBySymbol_Project_Id(projectId); - symbolStepRepository.deleteAllBySymbol_Project_Id(projectId); - testExecutionConfigRepository.deleteAllByProject_Id(projectId); - testReportRepository.deleteAllByProject_Id(projectId); - testRepository.deleteAllByProject_Id(projectId); - learnerResultStepRepository.deleteAllByResult_Project_Id(projectId); - learnerResultRepository.deleteAllByProject_Id(projectId); - learnerSetupRepository.deleteAllByProject_Id(projectId); - parameterizedSymbolRepository.deleteAllBySymbol_Project_Id(projectId); - symbolParameterRepository.deleteAllBySymbol_Project_Id(projectId); - uploadableFileRepository.deleteAllByProject_Id(projectId); - - // delete the screenshot directory - testReportDAO.deleteScreenshotDirectory(user, projectId); - - // clear relationships to members and owners first - project.getOwners().clear(); - project.getMembers().clear(); - projectRepository.save(project); - - // release all project locks - this.symbolPresenceService.releaseSymbolLocksByProject(projectId); - this.testPresenceService.releaseTestLocksByProject(projectId); - this.projectPresenceService.removeProjectFromPresenceMap(projectId); - - // delete the project directory - try { - fileDAO.deleteProjectDirectory(user, projectId); - projectRepository.delete(project); - } catch (IOException e) { - logger.info("The project has been deleted, the directory, however, not."); - } - - } - - public void delete(User user, List projectIds) { - for (Long id : projectIds) { - delete(user, id); - } - } - - public Project importProject(User user, ProjectExportableEntity projectExportableEntity) { - final ObjectMapper om = new ObjectMapper(); - - final Project project; - final List groups; - final List tests; - final List formulaSuites; - final List learnerSetups; - final List testExecutionConfigs; - - try { - project = om.readValue(projectExportableEntity.getProject().toString(), Project.class); - groups = Arrays.asList(om.readValue(projectExportableEntity.getGroups().toString(), SymbolGroup[].class)); - tests = Arrays.asList(om.readValue(projectExportableEntity.getTests().toString(), Test[].class)); - formulaSuites = Arrays.asList(om.readValue(projectExportableEntity.getFormulaSuites().toString(), LtsFormulaSuite[].class)); - learnerSetups = Arrays.asList(om.readValue(projectExportableEntity.getLearnerSetups().toString(), LearnerSetup[].class)); - testExecutionConfigs = Arrays.asList(om.readValue(projectExportableEntity.getTestExecutionConfigs().toString(), TestExecutionConfig[].class)); - } catch (IOException e) { - e.printStackTrace(); - throw new ValidationException("The input is not formatted correctly"); - } - - if (groups.isEmpty()) { - throw new ValidationException("There has to be a default group"); - } - - check(project); - - final var newProject = new Project(); - newProject.setName(project.getName()); - newProject.setDescription(project.getDescription()); - newProject.addOwner(user); - - final TestSuite rootTestSuite = new TestSuite(); - rootTestSuite.setName("Root"); - rootTestSuite.setProject(newProject); - newProject.getTests().add(rootTestSuite); - - final var createdProject = projectRepository.save(newProject); - createdProject.getEnvironments().addAll(project.getEnvironments().stream() - .map(e -> { - e.setProject(createdProject); - e.getVariables().forEach(v -> v.setEnvironment(e)); - e.getUrls().forEach(u -> u.setEnvironment(e)); - return environmentRepository.save(e); - }) - .collect(Collectors.toList()) - ); - - // newSymbolId -> oldSymbolId - Map symbolRefMap = new HashMap<>(); - - symbolGroupDAO.importGroups(user, createdProject, groups, symbolRefMap); - - /* oldTestId -> newTestId - * maps the exported testids to the corresponding newly created ones, - * enabling correct referencing when importing testExecutionConfigs - */ - Map configRefMap = new HashMap<>(); - - if (!tests.isEmpty()) { - testDAO.importTests(user, createdProject.getId(), tests, configRefMap, symbolRefMap); - } - - for (LtsFormulaSuite suite : formulaSuites) { - final LtsFormulaSuite createdSuite = ltsFormulaSuiteDAO.create(user, createdProject.getId(), suite); - for (LtsFormula formula : suite.getFormulas()) { - ltsFormulaDAO.create(user, createdProject.getId(), createdSuite.getId(), formula); - } - } - - if (!learnerSetups.isEmpty()) { - learnerSetupDAO.importLearnerSetups(user, createdProject, learnerSetups, symbolRefMap); - } - - if (!testExecutionConfigs.isEmpty()) { - testExecutionConfigDAO.importTestExecutionConfigs(user, createdProject, testExecutionConfigs, configRefMap); - } - - loadLazyRelations(createdProject); - return createdProject; - } - - private void check(Project project) { - checkProjectHasDefaultEnvironment(project); - checkEnvironmentsHaveDefaultUrl(project); - checkEnvironmentNamesAreUnique(project); - checkEnvironmentsHaveSameUrlNames(project); - checkEnvironmentsHaveSameVariableNames(project); - } - - /** - * Load objects that are connected with a project over a 'lazy' relation ship. - * - * @param project - * The project which needs the 'lazy' objects. - */ - private Project loadLazyRelations(Project project) { - Hibernate.initialize(project.getEnvironments()); - project.getEnvironments().forEach(env -> { - Hibernate.initialize(env.getUrls()); - Hibernate.initialize(env.getVariables()); - }); - Hibernate.initialize(project.getOwners()); - Hibernate.initialize(project.getMembers()); - return project; - } - - public void checkAccess(User user, Project project) { - if (project == null) { - throw new NotFoundException("The project does not exist."); - } - - if (project.getOwners().stream().noneMatch(u -> u.getId().equals(user.getId())) - && project.getMembers().stream().noneMatch(u -> u.getId().equals(user.getId())) - && user.getRole() != UserRole.ADMIN) { - throw new UnauthorizedException("You are not allowed to access the project."); - } - } - - public Project addOwners(User user, Long projectId, List ownerIds) { - final Project projectInDb = projectRepository.findById(projectId).orElse(null); - checkAccess(user, projectInDb); - - if (!projectInDb.getOwners().contains(user) && user.getRole() != UserRole.ADMIN) { - throw new UnauthorizedException("You are not allowed to add users as owners to the project."); - } - - ownerIds.forEach(ownerId -> { - projectInDb.removeMember(userDAO.getByID(ownerId)); - projectInDb.addOwner(userDAO.getByID(ownerId)); - }); - - checkProjectIntegrity(projectInDb); - - final Project updatedProject = projectRepository.save(projectInDb); - loadLazyRelations(updatedProject); - - return updatedProject; - } - - public Project addMembers(User user, Long projectId, List memberIds) { - final Project projectInDb = projectRepository.findById(projectId).orElse(null); - checkAccess(user, projectInDb); - - if (!projectInDb.getOwners().contains(user) && user.getRole() != UserRole.ADMIN) { - throw new UnauthorizedException("You are not allowed to add users as members to the project."); - } - - memberIds.forEach(memberId -> { - projectInDb.removeOwner(userDAO.getByID(memberId)); - projectInDb.addMember(userDAO.getByID(memberId)); - }); - - checkProjectIntegrity(projectInDb); - - final Project updatedProject = projectRepository.save(projectInDb); - loadLazyRelations(updatedProject); - - return updatedProject; - } - - public Project removeOwners(User user, Long projectId, List ownerIds) { - final Project projectInDb = projectRepository.findById(projectId).orElse(null); - checkAccess(user, projectInDb); - - if (!projectInDb.getOwners().contains(user) && user.getRole() != UserRole.ADMIN) { - throw new UnauthorizedException("You are not allowed to remove owners from the the project."); - } - - ownerIds.forEach(ownerId -> { - projectInDb.removeOwner(userDAO.getByID(ownerId)); - }); - - checkProjectIntegrity(projectInDb); - - final Project updatedProject = projectRepository.save(projectInDb); - loadLazyRelations(updatedProject); - - // remove owner presences from project and release locks - ownerIds.forEach(ownerId -> { - this.projectPresenceService.removeUserFromProjectPresence(ownerId, projectId); - this.testPresenceService.releaseUserLocksFromProject(ownerId, projectId); - this.symbolPresenceService.releaseUserLocksFromProject(ownerId, projectId); - }); - - return updatedProject; - } - - public Project removeMembers(User user, Long projectId, List memberIds) { - final Project projectInDb = projectRepository.findById(projectId).orElse(null); - checkAccess(user, projectInDb); - - if (!projectInDb.getOwners().contains(user) - && !(memberIds.size() == 1 && memberIds.contains(user.getId())) - && user.getRole() != UserRole.ADMIN) { - throw new UnauthorizedException("You are not allowed to remove members from the project."); - } - - memberIds.forEach(memberId -> { - projectInDb.removeMember(userDAO.getByID(memberId)); - }); - - final Project updatedProject = projectRepository.save(projectInDb); - loadLazyRelations(updatedProject); - - // remove member presences from project and release locks - memberIds.forEach(memberId -> { - this.projectPresenceService.removeUserFromProjectPresence(memberId, projectId); - this.testPresenceService.releaseUserLocksFromProject(memberId, projectId); - this.symbolPresenceService.releaseUserLocksFromProject(memberId, projectId); - }); - - return updatedProject; - } - - private void checkProjectIntegrity(Project project) { - //at least one owner has to remain - if (project.getOwners().isEmpty()) { - throw new ValidationException("There need to be at least one owner in the project."); - } - } - - private void checkEnvironmentNamesAreUnique(Project project) { - final var numberOfUniqueEnvironments = project.getEnvironments().stream() - .map(ProjectEnvironment::getName) - .collect(Collectors.toSet()) - .size(); - - if (numberOfUniqueEnvironments != project.getEnvironments().size()) { - throw new ValidationException("The names of the environments need to be unique."); - } - } - - private void checkEnvironmentsHaveDefaultUrl(Project project) { - for (ProjectEnvironment env : project.getEnvironments()) { - if (env.getUrls().stream().filter(ProjectUrl::isDefault).count() != 1) { - throw new ValidationException("An environment needs a default URL"); - } - } - } - - private void checkEnvironmentsHaveSameVariableNames(Project project) { - final var numberOfVariables = project.getEnvironments().stream() - .map(e -> e.getVariables().size()) - .collect(Collectors.toSet()) - .size(); - - if (numberOfVariables > 1) { - throw new ValidationException("Each environment has to have the same amount of variables"); - } - - final var variableNamesSet = project.getEnvironments().stream() - .map(ProjectEnvironment::getVariables) - .flatMap(Collection::stream) - .map(ProjectEnvironmentVariable::getName) - .collect(Collectors.toSet()); - - if (variableNamesSet.size() != project.getEnvironments().get(0).getVariables().size()) { - throw new ValidationException("The names of the variables are not equal in the environments"); - } - } - - private void checkEnvironmentsHaveSameUrlNames(Project project) { - final var numberOfUrls = project.getEnvironments().stream() - .map(e -> e.getUrls().size()).collect(Collectors.toSet()) - .size(); - - if (numberOfUrls > 1) { - throw new ValidationException("Each environment has to have the same amount of URLs"); - } - - final var urlNamesSet = project.getEnvironments().stream() - .map(ProjectEnvironment::getUrls) - .flatMap(Collection::stream) - .map(ProjectUrl::getName) - .collect(Collectors.toSet()); - - if (urlNamesSet.size() != project.getEnvironments().get(0).getUrls().size()) { - throw new ValidationException("The names of the urls are not equal in the environments"); - } - } - - private void checkProjectHasDefaultEnvironment(Project project) { - if (project.getEnvironments().stream().filter(ProjectEnvironment::isDefault).count() != 1) { - throw new ValidationException("There has to be exactly one environment"); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/dao/ProjectEnvironmentDAO.java b/backend/src/main/java/de/learnlib/alex/data/dao/ProjectEnvironmentDAO.java deleted file mode 100644 index 13cd86dfe..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/dao/ProjectEnvironmentDAO.java +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.dao; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.ForbiddenOperationException; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.data.entities.ProjectEnvironmentVariable; -import de.learnlib.alex.data.entities.ProjectUrl; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.data.entities.actions.rest.CallAction; -import de.learnlib.alex.data.entities.actions.web.GotoAction; -import de.learnlib.alex.data.repositories.ProjectEnvironmentRepository; -import de.learnlib.alex.data.repositories.ProjectEnvironmentVariableRepository; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.data.repositories.ProjectUrlRepository; -import de.learnlib.alex.data.repositories.SymbolActionRepository; -import de.learnlib.alex.learning.repositories.LearnerSetupRepository; -import de.learnlib.alex.testing.repositories.TestExecutionConfigRepository; -import de.learnlib.alex.testing.repositories.TestReportRepository; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; -import javax.validation.ValidationException; -import org.apache.shiro.authz.UnauthorizedException; -import org.hibernate.Hibernate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(rollbackFor = Exception.class) -public class ProjectEnvironmentDAO { - - private final ProjectDAO projectDAO; - private final ProjectRepository projectRepository; - private final ProjectEnvironmentRepository environmentRepository; - private final ProjectEnvironmentVariableRepository variableRepository; - private final ProjectUrlRepository urlRepository; - private final SymbolActionRepository symbolActionRepository; - private final TestReportRepository testReportRepository; - private final LearnerSetupRepository learnerSetupRepository; - private final TestExecutionConfigRepository testExecutionConfigRepository; - - @Autowired - public ProjectEnvironmentDAO(ProjectDAO projectDAO, - ProjectRepository projectRepository, - ProjectEnvironmentRepository environmentRepository, - ProjectEnvironmentVariableRepository variableRepository, - ProjectUrlRepository urlRepository, - SymbolActionRepository symbolActionRepository, - TestReportRepository testReportRepository, - LearnerSetupRepository learnerSetupRepository, - TestExecutionConfigRepository testExecutionConfigRepository) { - this.projectDAO = projectDAO; - this.projectRepository = projectRepository; - this.environmentRepository = environmentRepository; - this.variableRepository = variableRepository; - this.urlRepository = urlRepository; - this.symbolActionRepository = symbolActionRepository; - this.testReportRepository = testReportRepository; - this.learnerSetupRepository = learnerSetupRepository; - this.testExecutionConfigRepository = testExecutionConfigRepository; - } - - public ProjectEnvironment create(User user, Long projectId, ProjectEnvironment environment) { - final Project project = projectRepository.findById(projectId).orElse(null); - projectDAO.checkAccess(user, project); - checkPermissions(user, project); - - if (environmentRepository.findByProject_IdAndName(projectId, environment.getName()) != null) { - throw new ValidationException("There has to be at least one environment."); - } - - List urls = new ArrayList<>(); - List variables = new ArrayList<>(); - final List envs = environmentRepository.findAllByProject_Id(projectId); - if (envs.size() > 0) { - urls = envs.get(0).getUrls(); - variables = envs.get(0).getVariables(); - } - - final ProjectEnvironment envToCreate = new ProjectEnvironment(); - envToCreate.setName(environment.getName()); - envToCreate.setProject(project); - envToCreate.setDefault(environment.isDefault()); - - final ProjectEnvironment projectEnvironment = environmentRepository.save(envToCreate); - project.getEnvironments().add(projectEnvironment); - projectRepository.save(project); - - final List createdUrls = new ArrayList<>(); - for (ProjectUrl url : urls) { - final ProjectUrl u = new ProjectUrl(); - u.setName(url.getName()); - u.setEnvironment(projectEnvironment); - u.setUrl(url.getUrl()); - u.setDefault(url.isDefault()); - createdUrls.add(u); - } - urlRepository.saveAll(createdUrls); - projectEnvironment.getUrls().addAll(createdUrls); - - final List createdVariables = new ArrayList<>(); - for (ProjectEnvironmentVariable var : variables) { - final ProjectEnvironmentVariable v = new ProjectEnvironmentVariable(); - v.setEnvironment(projectEnvironment); - v.setName(var.getName()); - v.setValue(var.getValue()); - createdVariables.add(v); - } - variableRepository.saveAll(createdVariables); - projectEnvironment.getVariables().addAll(createdVariables); - - environmentRepository.save(projectEnvironment); - return loadLazyRelations(projectEnvironment); - } - - public void delete(User user, Long projectId, Long environmentId) { - final Project project = projectRepository.findById(projectId).orElse(null); - final ProjectEnvironment environment = environmentRepository.findById(environmentId).orElse(null); - checkAccess(user, project, environment); - checkPermissions(user, project); - - if (environmentRepository.findAllByProject_Id(projectId).size() == 1) { - throw new ValidationException("There has to be at least one environment."); - } - - if (!testExecutionConfigRepository.findAllByProject_IdAndEnvironment_Id(projectId, environmentId).isEmpty()) { - throw new ForbiddenOperationException("The environment " + environment.getName() + " is associated with one or more test configs."); - } - - if (!learnerSetupRepository.findAllByProject_IdAndEnvironment_Id(projectId, environmentId).isEmpty()) { - throw new ForbiddenOperationException("The environment " + environment.getName() + " is associated with one or more learner setups."); - } - - // select next best default environment - if (environment.isDefault()) { - final List envs = environmentRepository.findAllByProject_Id(projectId); - final ProjectEnvironment env = envs.stream().filter(e -> !e.isDefault()).findFirst().orElse(null); - env.setDefault(true); - environmentRepository.save(env); - } - - // delete test reports that have been executed in the environment - testReportRepository.deleteAllByEnvironment_Id(environment.getId()); - - project.getEnvironments().remove(environment); - projectRepository.save(project); - environmentRepository.delete(environment); - } - - public ProjectEnvironment update(User user, Long projectId, Long envId, ProjectEnvironment env) { - final Project project = projectRepository.findById(projectId).orElse(null); - final ProjectEnvironment envInDb = environmentRepository.findById(envId).orElse(null); - checkAccess(user, project, envInDb); - checkPermissions(user, project); - - if (environmentRepository.findByProject_IdAndNameAndIdNot(projectId, env.getName(), envInDb.getId()) != null) { - throw new ValidationException("The name of the environment already exists"); - } - - envInDb.setName(env.getName()); - - // switch default environment - if (env.isDefault() && !envInDb.isDefault()) { - final var defaultEnv = environmentRepository.findByProject_IdAndIs_Default(projectId, true); - defaultEnv.setDefault(false); - environmentRepository.save(defaultEnv); - envInDb.setDefault(true); - } - - final ProjectEnvironment updatedEnv = environmentRepository.save(envInDb); - return loadLazyRelations(updatedEnv); - } - - public List getAll(User user, Long projectId) { - final Project project = projectRepository.findById(projectId).orElse(null); - projectDAO.checkAccess(user, project); - - final List environments = environmentRepository.findAllByProject_Id(projectId); - environments.forEach(ProjectEnvironmentDAO::loadLazyRelations); - return environments; - } - - public ProjectEnvironment getByID(User user, Long envId) { - final ProjectEnvironment env = environmentRepository.findById(envId).orElse(null); - checkAccess(user, env.getProject(), env); - return ProjectEnvironmentDAO.loadLazyRelations(env); - } - - public ProjectEnvironmentVariable createVariable( - User user, - Long projectId, - Long environmentId, - ProjectEnvironmentVariable variable - ) { - final Project project = projectRepository.findById(projectId).orElse(null); - final ProjectEnvironment env = environmentRepository.findById(environmentId).orElse(null); - checkAccess(user, project, env); - checkPermissions(user, project); - - if (variableRepository.findByEnvironment_IdAndName(environmentId, variable.getName()) != null) { - throw new ValidationException("The name of the variable already exists"); - } - - final List variablesToCreate = new ArrayList<>(); - final List envs = environmentRepository.findAllByProject_Id(projectId); - for (ProjectEnvironment e : envs) { - final ProjectEnvironmentVariable v = new ProjectEnvironmentVariable(); - v.setName(variable.getName()); - v.setValue(variable.getValue()); - v.setEnvironment(e); - variablesToCreate.add(v); - e.getVariables().add(v); - } - - variableRepository.saveAll(variablesToCreate); - return variablesToCreate.stream().filter(v -> v.getEnvironment().equals(env)).findFirst().orElse(null); - } - - public void deleteVariable(User user, Long projectId, Long environmentId, Long variableId) { - final Project project = projectRepository.findById(projectId).orElse(null); - final ProjectEnvironment env = environmentRepository.findById(environmentId).orElse(null); - final ProjectEnvironmentVariable variable = variableRepository.findById(variableId).orElse(null); - checkAccess(user, project, env, variable); - checkPermissions(user, project); - - variableRepository.deleteAllByEnvironment_Project_IdAndName(projectId, variable.getName()); - } - - public ProjectEnvironmentVariable updateVariable( - User user, - Long projectId, - Long environmentId, - Long variableId, - ProjectEnvironmentVariable variable - ) { - final Project project = projectRepository.findById(projectId).orElse(null); - final ProjectEnvironment env = environmentRepository.findById(environmentId).orElse(null); - final ProjectEnvironmentVariable variableInDb = variableRepository.findById(variableId).orElse(null); - checkAccess(user, project, env, variableInDb); - checkPermissions(user, project); - - if (variableRepository.findByEnvironment_IdAndNameAndIdNot(environmentId, variable.getName(), variableId) != null) { - throw new ValidationException("The name of the variable already exists"); - } - - final var variables = variableRepository.findAllByEnvironment_Project_IdAndName(projectId, variableInDb.getName()); - for (ProjectEnvironmentVariable v : variables) { - v.setName(variable.getName()); - } - if (!variables.isEmpty()) { - variableRepository.saveAll(variables); - } - - variableInDb.setName(variable.getName()); - variableInDb.setValue(variable.getValue()); - return variableRepository.save(variableInDb); - } - - public List createUrls(User user, Long projectId, Long environmentId, ProjectUrl url) { - final Project project = projectRepository.findById(projectId).orElse(null); - final ProjectEnvironment env = environmentRepository.findById(environmentId).orElse(null); - checkAccess(user, project, env); - checkPermissions(user, project); - - if (urlRepository.findByEnvironment_IdAndName(environmentId, url.getName()) != null) { - throw new ValidationException("The name for the URL already exists."); - } - - // create the url for each environment - final List urlsToCreate = new ArrayList<>(); - final List envs = environmentRepository.findAllByProject_Id(projectId); - for (ProjectEnvironment e : envs) { - final ProjectUrl u = new ProjectUrl(); - u.setName(url.getName()); - u.setEnvironment(e); - u.setUrl(url.getUrl()); - urlsToCreate.add(u); - } - - return urlRepository.saveAll(urlsToCreate); - } - - public void deleteUrl(User user, Long projectId, Long environmentId, Long urlId) { - final Project project = projectRepository.findById(projectId).orElse(null); - final ProjectEnvironment env = environmentRepository.findById(environmentId).orElse(null); - final ProjectUrl url = urlRepository.findById(urlId).orElse(null); - checkAccess(user, project, env, url); - checkPermissions(user, project); - - final List envs = environmentRepository.findAllByProject_Id(projectId); - for (ProjectEnvironment e : envs) { - if (e.getUrls().size() == 1) { - throw new ValidationException("Environments require at least one URL."); - } - - final var urls = e.getUrls().stream() - .filter(u -> !u.getName().equals(url.getName())) - .collect(Collectors.toList()); - - e.setUrls(urls); - urlRepository.deleteByEnvironment_IdAndName(e.getId(), url.getName()); - - // make new default url - if (url.isDefault()) { - e.getUrls().get(0).setDefault(true); - urlRepository.save(e.getUrls().get(0)); - } - } - - environmentRepository.saveAll(envs); - - // set base url of actions that reference url to the new base url - final List actions = symbolActionRepository.findAllWithBaseUrl(projectId, url.getName()); - for (final SymbolAction a : actions) { - if (a instanceof CallAction) { - ((CallAction) a).setBaseUrl(env.getDefaultUrl().getName()); - } else if (a instanceof GotoAction) { - ((GotoAction) a).setBaseUrl(env.getDefaultUrl().getName()); - } - } - symbolActionRepository.saveAll(actions); - } - - public List updateUrls(User user, Long projectId, Long envId, Long urlId, ProjectUrl url) { - final Project project = projectRepository.findById(projectId).orElse(null); - final ProjectEnvironment env = environmentRepository.findById(envId).orElse(null); - final ProjectUrl urlInDb = urlRepository.findById(urlId).orElse(null); - checkAccess(user, project, env, urlInDb); - checkPermissions(user, project); - - if (urlRepository.findByEnvironment_IdAndNameAndIdNot(envId, url.getName(), urlInDb.getId()) != null) { - throw new ValidationException("The name of the URL already exists."); - } - - // update default url - if (url.isDefault() && !urlInDb.isDefault()) { - List urls = urlRepository.findByEnvironment_Project_IdAndIsDefault(projectId, true); - urls.forEach(u -> u.setDefault(false)); - urlRepository.saveAll(urls); - - urls = urlRepository.findByEnvironment_Project_IdAndName(projectId, urlInDb.getName()); - urls.forEach(u -> u.setDefault(true)); - urlRepository.saveAll(urls); - } - - final List updatedUrls = new ArrayList<>(); - final String originalName = urlInDb.getName(); - - urlInDb.setUrl(url.getUrl()); - urlInDb.setName(url.getName()); - updatedUrls.add(urlRepository.save(urlInDb)); - - // update the name of all other urls if the name changed - if (!url.getName().equals(originalName)) { - final List envs = environmentRepository.findAllByProject_Id(projectId); - for (ProjectEnvironment e : envs) { - for (ProjectUrl u : e.getUrls()) { - if (u.getName().equals(originalName)) { - u.setName(url.getName()); - updatedUrls.add(urlRepository.save(u)); - } - } - } - - // update actions that reference the base url - final List actions = symbolActionRepository.findAllWithBaseUrl(projectId, originalName); - for (final SymbolAction a : actions) { - if (a instanceof CallAction) { - ((CallAction) a).setBaseUrl(url.getName()); - } else if (a instanceof GotoAction) { - ((GotoAction) a).setBaseUrl(url.getName()); - } - } - symbolActionRepository.saveAll(actions); - } - - return updatedUrls; - } - - public void checkAccess(User user, Project project, ProjectEnvironment env) - throws NotFoundException, UnauthorizedException { - projectDAO.checkAccess(user, project); - - if (env == null) { - throw new NotFoundException("The environment could not be found."); - } - - if (!env.getProjectId().equals(project.getId())) { - throw new UnauthorizedException("You are not allowed to access the environment."); - } - } - - public void checkAccess(User user, Project project, ProjectEnvironment env, ProjectUrl url) - throws NotFoundException, UnauthorizedException { - checkAccess(user, project, env); - - if (url == null) { - throw new NotFoundException("The url could not be found."); - } - - if (!url.getEnvironmentId().equals(env.getId())) { - throw new UnauthorizedException("You are not allowed to access the url."); - } - } - - public void checkAccess(User user, Project project, ProjectEnvironment env, ProjectEnvironmentVariable variable) - throws NotFoundException, UnauthorizedException { - checkAccess(user, project, env); - - if (variable == null) { - throw new NotFoundException("The variable could not be found."); - } - - if (!variable.getEnvironmentId().equals(env.getId())) { - throw new UnauthorizedException("You are not allowed to access the variable."); - } - } - - public void checkPermissions(User user, Project project) { - if (project.getOwners().stream().noneMatch(u -> u.getId().equals(user.getId()))) { - throw new UnauthorizedException("You need to be an owner to do that."); - } - } - - public static ProjectEnvironment loadLazyRelations(ProjectEnvironment environment) { - Hibernate.initialize(environment.getUrls()); - Hibernate.initialize(environment.getVariables()); - return environment; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/dao/SymbolDAO.java b/backend/src/main/java/de/learnlib/alex/data/dao/SymbolDAO.java deleted file mode 100644 index f2fad4707..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/dao/SymbolDAO.java +++ /dev/null @@ -1,736 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.dao; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.EntityLockedException; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.data.entities.SymbolActionStep; -import de.learnlib.alex.data.entities.SymbolGroup; -import de.learnlib.alex.data.entities.SymbolOutputMapping; -import de.learnlib.alex.data.entities.SymbolPSymbolStep; -import de.learnlib.alex.data.entities.SymbolParameter; -import de.learnlib.alex.data.entities.SymbolStep; -import de.learnlib.alex.data.entities.actions.misc.CreateLabelAction; -import de.learnlib.alex.data.entities.actions.misc.JumpToLabelAction; -import de.learnlib.alex.data.entities.actions.rest.CallAction; -import de.learnlib.alex.data.entities.actions.web.GotoAction; -import de.learnlib.alex.data.repositories.ParameterizedSymbolRepository; -import de.learnlib.alex.data.repositories.ProjectEnvironmentRepository; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.data.repositories.SymbolActionRepository; -import de.learnlib.alex.data.repositories.SymbolGroupRepository; -import de.learnlib.alex.data.repositories.SymbolPSymbolStepRepository; -import de.learnlib.alex.data.repositories.SymbolParameterRepository; -import de.learnlib.alex.data.repositories.SymbolRepository; -import de.learnlib.alex.data.repositories.SymbolStepRepository; -import de.learnlib.alex.data.utils.SymbolOutputMappingUtils; -import de.learnlib.alex.learning.dao.LearnerSetupDAO; -import de.learnlib.alex.testing.dao.TestDAO; -import de.learnlib.alex.testing.entities.TestCase; -import de.learnlib.alex.testing.entities.TestCaseStep; -import de.learnlib.alex.testing.repositories.TestCaseStepRepository; -import de.learnlib.alex.testing.repositories.TestExecutionResultRepository; -import de.learnlib.alex.websocket.services.SymbolPresenceService; -import net.automatalib.graphs.base.compact.CompactSimpleGraph; -import net.automatalib.util.graphs.scc.SCCs; -import org.apache.shiro.authz.UnauthorizedException; -import org.hibernate.Hibernate; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.stereotype.Service; -import org.springframework.transaction.TransactionSystemException; -import org.springframework.transaction.annotation.Transactional; - -import javax.validation.ValidationException; -import java.sql.Timestamp; -import java.text.SimpleDateFormat; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * Implementation of a SymbolDAO using Spring Data. - */ -@Service -@Transactional(rollbackFor = Exception.class) -public class SymbolDAO { - - /** The format for archived symbols. */ - private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd-HH:mm:ss"); - - private static final Logger logger = LoggerFactory.getLogger(SymbolDAO.class); - - private final ProjectRepository projectRepository; - private final ProjectDAO projectDAO; - private final SymbolGroupDAO symbolGroupDAO; - private final SymbolGroupRepository symbolGroupRepository; - private final SymbolRepository symbolRepository; - private final SymbolActionRepository symbolActionRepository; - private final SymbolParameterRepository symbolParameterRepository; - private final SymbolStepRepository symbolStepRepository; - private final ParameterizedSymbolDAO parameterizedSymbolDAO; - private final SymbolPSymbolStepRepository symbolPSymbolStepRepository; - private final ParameterizedSymbolRepository parameterizedSymbolRepository; - private final TestCaseStepRepository testCaseStepRepository; - private final TestExecutionResultRepository testExecutionResultRepository; - private final ProjectEnvironmentRepository projectEnvironmentRepository; - private final ObjectMapper objectMapper; - private final SymbolParameterDAO symbolParameterDAO; - private final SymbolPresenceService symbolPresenceService; - private final TestDAO testDAO; - private final LearnerSetupDAO learnerSetupDAO; - - @Autowired - public SymbolDAO(ProjectRepository projectRepository, ProjectDAO projectDAO, - SymbolGroupRepository symbolGroupRepository, SymbolRepository symbolRepository, - SymbolActionRepository symbolActionRepository, SymbolGroupDAO symbolGroupDAO, - SymbolParameterRepository symbolParameterRepository, SymbolStepRepository symbolStepRepository, - ParameterizedSymbolDAO parameterizedSymbolDAO, - ParameterizedSymbolRepository parameterizedSymbolRepository, - SymbolPSymbolStepRepository symbolPSymbolStepRepository, - TestCaseStepRepository testCaseStepRepository, - TestExecutionResultRepository testExecutionResultRepository, - ProjectEnvironmentRepository projectEnvironmentRepository, - ObjectMapper objectMapper, - @Lazy SymbolParameterDAO symbolParameterDAO, - @Lazy SymbolPresenceService symbolPresenceService, - @Lazy TestDAO testDAO, - @Lazy LearnerSetupDAO learnerSetupDAO) { - this.projectRepository = projectRepository; - this.projectDAO = projectDAO; - this.symbolGroupRepository = symbolGroupRepository; - this.symbolRepository = symbolRepository; - this.symbolActionRepository = symbolActionRepository; - this.symbolGroupDAO = symbolGroupDAO; - this.symbolParameterRepository = symbolParameterRepository; - this.symbolStepRepository = symbolStepRepository; - this.parameterizedSymbolDAO = parameterizedSymbolDAO; - this.parameterizedSymbolRepository = parameterizedSymbolRepository; - this.symbolPSymbolStepRepository = symbolPSymbolStepRepository; - this.testCaseStepRepository = testCaseStepRepository; - this.testExecutionResultRepository = testExecutionResultRepository; - this.projectEnvironmentRepository = projectEnvironmentRepository; - this.objectMapper = objectMapper; - this.symbolParameterDAO = symbolParameterDAO; - this.symbolPresenceService = symbolPresenceService; - this.testDAO = testDAO; - this.learnerSetupDAO = learnerSetupDAO; - } - - public List importSymbols( - User user, - Project project, - List symbols, - Map newSymbolIdToOldSymbolId - ) { - final List importedSymbols = new ArrayList<>(); - - for (Symbol symbol : symbols) { - var oldId = symbol.getId(); - symbol.setId(null); - - var createdSymbol = create(user, project.getId(), symbol); - importedSymbols.add(createdSymbol); - - newSymbolIdToOldSymbolId.put(createdSymbol.getId(), oldId); - } - - importedSymbols.forEach(SymbolDAO::loadLazyRelations); - return importedSymbols; - } - - public Symbol create(User user, Long projectId, Symbol symbol) { - try { - final Symbol createdSymbol = createOne(user, projectId, symbol); - final Map> symbolStepMap = new HashMap<>(); - symbolStepMap.put(createdSymbol.getId(), symbol.getSteps()); - saveSymbolSteps(projectId, Collections.singletonList(createdSymbol), symbolStepMap); - return createdSymbol; - } catch (Exception e) { - logger.info("Symbol creation failed:", e); - throw e; - } - } - - public List create(User user, Long projectId, List symbols) { - try { - final List createdSymbols = new ArrayList<>(); - final Map> symbolStepMap = new HashMap<>(); - for (Symbol symbol : symbols) { - final Symbol createdSymbol = createOne(user, projectId, symbol); - createdSymbols.add(createdSymbol); - symbolStepMap.put(createdSymbol.getId(), symbol.getSteps()); - } - - saveSymbolSteps(projectId, createdSymbols, symbolStepMap); - return createdSymbols; - } catch (Exception e) { - logger.info("Symbols creation failed:", e); - throw e; - } - } - - private Symbol createOne(User user, Long projectId, Symbol symbol) { - final Project project = projectRepository.findById(projectId).orElse(null); - projectDAO.checkAccess(user, project); - symbol.setProject(project); - - - final SymbolGroup group; - if (symbol.getGroup() == null || symbol.getGroup().getId() == null) { - group = symbolGroupRepository.findFirstByProject_IdOrderByIdAsc(projectId); // default group - } else { - group = symbolGroupRepository.findById(symbol.getGroup().getId()).orElse(null); - symbolGroupDAO.checkAccess(user, project, group); - } - - // make sure the name of the symbol is unique within its group - if (symbolRepository.findOneByGroup_IdAndName(group.getId(), symbol.getName()) != null) { - throw new ValidationException("To create a symbol its name must be unique within its group."); - } - - // create default symbols - final Symbol symbolToCreate = new Symbol(); - symbolToCreate.setName(symbol.getName()); - symbolToCreate.setProject(project); - symbolToCreate.setGroup(group); - symbolToCreate.setDescription(symbol.getDescription()); - symbolToCreate.setExpectedResult(symbol.getExpectedResult()); - symbolToCreate.setHidden(symbol.isHidden()); - symbolToCreate.setSuccessOutput(symbol.getSuccessOutput()); - symbolToCreate.setLastUpdatedBy(user); - group.getSymbols().add(symbolToCreate); - project.getSymbols().add(symbolToCreate); - - // update related references - Symbol createdSymbol = symbolRepository.save(symbolToCreate); - symbolGroupRepository.save(group); - projectRepository.save(project); - - // save input and output parameters - createdSymbol.setInputs(symbol.getInputs()); - createdSymbol.setOutputs(symbol.getOutputs()); - createdSymbol.getInputs().forEach(input -> input.setSymbol(createdSymbol)); - createdSymbol.getOutputs().forEach(output -> output.setSymbol(createdSymbol)); - symbolParameterRepository.saveAll(createdSymbol.getInputs()); - symbolParameterRepository.saveAll(createdSymbol.getOutputs()); - - return createdSymbol; - } - - public void saveSymbolSteps( - Long projectId, - List createdSymbols, - Map> symbolStepMap - ) { - final List allSymbols = symbolRepository.findAllByProject_Id(projectId); - final Map symbolMap = new HashMap<>(); - allSymbols.forEach(symbol -> symbolMap.put(symbol.getId(), symbol)); - - for (Symbol createdSymbol : createdSymbols) { - createdSymbol.setSteps(symbolStepMap.get(createdSymbol.getId())); - checkLabelsConsistency(createdSymbol); - - for (int i = 0; i < createdSymbol.getSteps().size(); i++) { - final SymbolStep step = createdSymbol.getSteps().get(i); - step.setPosition(i); - step.setSymbol(createdSymbol); - - if (step instanceof SymbolActionStep) { - final SymbolActionStep actionStep = (SymbolActionStep) step; - actionStep.getAction().setSymbol(createdSymbol); - checkIfBaseUrlExists(projectId, actionStep.getAction()); - symbolActionRepository.save(actionStep.getAction()); - } else if (step instanceof SymbolPSymbolStep) { - // first, set the reference to the corresponding symbol - final SymbolPSymbolStep symbolStep = (SymbolPSymbolStep) step; - final long symbolId = symbolStep.getPSymbol().getSymbol().getId(); - final Symbol symbol = symbolMap.get(symbolId); - if (symbol == null) { - throw new NotFoundException("The symbol with the id " + symbolId + " does not exist."); - } - symbolStep.getPSymbol().setSymbol(symbol); - - // then, set the referenced symbol parameters - final Map parameterMap = new HashMap<>(); - symbol.getInputs().forEach(input -> parameterMap.put(input.getName(), input)); - symbolStep.getPSymbol().getParameterValues().forEach(pv -> { - pv.setParameter(parameterMap.get(pv.getParameter().getName())); - }); - - // finally, save the parameterized symbol - parameterizedSymbolDAO.create(symbolStep.getPSymbol()); - } - } - - symbolStepRepository.saveAll(createdSymbol.getSteps()); - } - } - - private void checkIfBaseUrlExists(Long projectId, SymbolAction action) { - final String baseUrl; - if (action instanceof CallAction) { - baseUrl = ((CallAction) action).getBaseUrl(); - } else if (action instanceof GotoAction) { - baseUrl = ((GotoAction) action).getBaseUrl(); - } else { - return; - } - - if (baseUrl == null || baseUrl.trim().equals("")) { - throw new ValidationException("The base URL may not be empty."); - } - - final ProjectEnvironment env = projectEnvironmentRepository.findAllByProject_Id(projectId).get(0); - if (env.getUrls().stream().noneMatch(u -> u.getName().equals(baseUrl))) { - throw new ValidationException("The URL '" + baseUrl + "' does not exist within the project."); - } - } - - public List getByIds(User user, Long projectId, List ids) { - final Project project = projectRepository.findById(projectId).orElse(null); - - // get the symbols - final List symbols = symbolRepository.findAllByIdIn(ids); - for (Symbol symbol : symbols) { - checkAccess(user, project, symbol); - } - - // load the lazy relations - symbols.forEach(SymbolDAO::loadLazyRelations); - return symbols; - } - - public List getAll(User user, Long projectId) { - final Project project = projectRepository.findById(projectId).orElse(null); - projectDAO.checkAccess(user, project); - - final List symbols = symbolRepository.findAllByProject_Id(projectId); - symbols.forEach(SymbolDAO::loadLazyRelations); - return symbols; - } - - public List getAll(User user, Long projectId, boolean hidden) { - final Project project = projectRepository.findById(projectId).orElse(null); - projectDAO.checkAccess(user, project); - - return symbolRepository.findAllByProject_IdAndHidden(projectId, hidden).stream() - .peek(SymbolDAO::loadLazyRelations) - .toList(); - } - - public Symbol get(User user, Long projectId, Long id) { - final Project project = projectRepository.findById(projectId).orElse(null); - return get(user, project, id); - } - - public Symbol get(User user, Project project, Long symbolId) { - final Symbol symbol = symbolRepository.findById(symbolId).orElse(null); - checkAccess(user, project, symbol); - loadLazyRelations(symbol); - return symbol; - } - - public Symbol update(User user, Long projectId, Symbol symbol) { - try { - return doUpdate(user, projectId, symbol); - } catch (TransactionSystemException | DataIntegrityViolationException e) { - logger.info("Symbol update failed:", e); - throw new ValidationException("Symbol could not be updated.", e); - } catch (IllegalStateException e) { - throw new ValidationException("Could not update the symbol because it is not valid.", e); - } - } - - public List update(User user, Long projectId, List symbols) { - try { - final List updatedSymbols = new ArrayList<>(); - for (Symbol symbol : symbols) { - updatedSymbols.add(doUpdate(user, projectId, symbol)); - } - return updatedSymbols; - } catch (IllegalStateException e) { - throw new ValidationException("Could not update the Symbols because one is not valid.", e); - } catch (NotFoundException e) { - throw new NotFoundException("Could not update the Symbol because it was nowhere to be found.", e); - } - } - - private void checkLabelsConsistency(Symbol symbol) { - final List labels = symbol.getSteps().stream() - .filter(s -> s instanceof SymbolActionStep) - .map(s -> ((SymbolActionStep) s).getAction()) - .filter(a -> a instanceof CreateLabelAction) - .map(a -> ((CreateLabelAction) a).getLabel()) - .collect(Collectors.toList()); - - if (labels.size() != new HashSet<>(labels).size()) { - throw new ValidationException("The labels are not unique."); - } - - final List labelsToJumpTo = symbol.getSteps().stream() - .filter(s -> s instanceof SymbolActionStep) - .map(s -> ((SymbolActionStep) s).getAction()) - .filter(a -> a instanceof JumpToLabelAction) - .map(a -> ((JumpToLabelAction) a).getLabel()) - .collect(Collectors.toList()); - - for (String label : labelsToJumpTo) { - if (!labels.contains(label)) { - throw new ValidationException("Label " + label + " has not been created."); - } - } - } - - private void checkIfOutputMappingNamesAreUnique(Symbol symbol) { - final ArrayList oms = new ArrayList<>(); - symbol.getSteps().stream() - .filter(s -> s instanceof SymbolPSymbolStep) - .forEach(s -> oms.addAll(((SymbolPSymbolStep) s).getPSymbol().getOutputMappings())); - - SymbolOutputMappingUtils.checkIfMappedNamesAreUnique(oms); - } - - private Symbol doUpdate(User user, Long projectId, Symbol symbol) { - final Project project = projectRepository.findById(projectId).orElse(null); - checkAccess(user, project, symbol); - checkRunningProcesses(user, project, symbol); - - // check lock status - this.symbolPresenceService.checkSymbolLockStatus(projectId, symbol.getId(), user.getId()); - - // make sure the name of the symbol is unique within its group - final Symbol symbolWithSameName = symbolRepository.findOneByGroup_IdAndName(symbol.getGroupId(), symbol.getName()); - if (symbolWithSameName != null && !symbolWithSameName.getId().equals(symbol.getId())) { - throw new ValidationException("To update a symbol its name must be unique within its group."); - } - - checkLabelsConsistency(symbol); - checkIfOutputMappingNamesAreUnique(symbol); - - // update meta info - Symbol symbolInDb = symbolRepository.findById(symbol.getId()).orElse(null); - symbolInDb.setName(symbol.getName()); - symbolInDb.setDescription(symbol.getDescription()); - symbolInDb.setExpectedResult(symbol.getExpectedResult()); - symbolInDb.setUpdatedOn(ZonedDateTime.now()); - symbolInDb.setLastUpdatedBy(user); - symbolInDb.setSuccessOutput(symbol.getSuccessOutput()); - - // update steps - if (symbol.getSteps().isEmpty()) { - symbolActionRepository.deleteAllBySymbol_Id(symbol.getId()); - symbolStepRepository.deleteAllBySymbol_Id(symbol.getId()); - symbolInDb.getSteps().clear(); - symbolStepRepository.deleteAllBySymbol_Id(symbolInDb.getId()); - } else { - final List idsOfStepsToKeep = symbol.getSteps().stream() - .filter(s -> s.getId() != null) - .map(SymbolStep::getId) - .collect(Collectors.toList()); - - if (idsOfStepsToKeep.isEmpty()) { - symbolStepRepository.deleteAllBySymbol_Id(symbolInDb.getId()); - } else { - symbolStepRepository.deleteAllBySymbol_IdAndIdNotIn(symbolInDb.getId(), idsOfStepsToKeep); - } - - symbolInDb.setSteps(symbol.getSteps()); - - // update references, save action and parameterized symbols - for (int i = 0; i < symbolInDb.getSteps().size(); i++) { - final SymbolStep step = symbolInDb.getSteps().get(i); - step.setPosition(i); - step.setSymbol(symbolInDb); - if (step instanceof SymbolActionStep) { - final SymbolActionStep actionStep = ((SymbolActionStep) step); - actionStep.getAction().setSymbol(symbolInDb); - symbolActionRepository.save(actionStep.getAction()); - } else if (step instanceof SymbolPSymbolStep) { - final SymbolPSymbolStep symbolStep = (SymbolPSymbolStep) step; - symbolStep.setPSymbol(parameterizedSymbolDAO.create(symbolStep.getPSymbol())); - } - } - symbolStepRepository.saveAll(symbolInDb.getSteps()); - } - - beforeSymbolSave(symbolInDb); - symbolInDb = symbolRepository.save(symbolInDb); - checkForCycles(symbolInDb); - - return symbolInDb; - } - - public Symbol move(User user, Long projectId, Long symbolId, Long newGroupId) { - return move(user, projectId, Collections.singletonList(symbolId), newGroupId).get(0); - } - - public List move(User user, Long projectId, List symbolIds, Long newGroupId) { - - final Project project = projectRepository.findById(projectId).orElse(null); - final List symbols = symbolRepository.findAllByIdIn(symbolIds); - for (Symbol symbol : symbols) { - checkAccess(user, project, symbol); - - // check symbol lock status - this.symbolPresenceService.checkSymbolLockStatusStrict(projectId, symbol.getId(), user.getId()); - - // make sure the name of the symbol is unique within the new group - if (symbolRepository.findOneByGroup_IdAndName(newGroupId, symbol.getName()) != null) { - throw new ValidationException("At least one symbols name is already present in the target group."); - } - } - - for (Symbol symbol : symbols) { - final SymbolGroup oldGroup = symbolGroupRepository.findById(symbol.getGroupId()).orElse(null); - final SymbolGroup newGroup = symbolGroupRepository.findById(newGroupId).orElse(null); - symbolGroupDAO.checkAccess(user, project, newGroup); - - if (!newGroup.equals(oldGroup)) { - oldGroup.getSymbols().remove(symbol); - newGroup.addSymbol(symbol); - - symbolGroupRepository.save(oldGroup); - symbolGroupRepository.save(newGroup); - } - } - - final List movedSymbols = symbolRepository.saveAll(symbols); - movedSymbols.forEach(SymbolDAO::loadLazyRelations); - return movedSymbols; - } - - private void checkForCycles(Symbol symbol) { - // is there a circular dependency between symbol steps? - if (symbol.getSteps().stream() - .filter(s -> s instanceof SymbolPSymbolStep) - .collect(Collectors.toList()).size() > 0) { - final List allSymbols = symbolRepository.findAllByProject_Id(symbol.getProject().getId()); - if (containsCycles(allSymbols)) { - throw new ValidationException("Circular dependency found."); - } - } - } - - private boolean containsCycles(List symbols) { - final Map map = new HashMap<>(); - - final CompactSimpleGraph graph = new CompactSimpleGraph<>(); - symbols.forEach(symbol -> { - final int state = graph.addNode(); - map.put(symbol.getId(), state); - }); - - for (final Symbol symbol : symbols) { - for (final SymbolStep step : symbol.getSteps()) { - if (step instanceof SymbolPSymbolStep) { - final SymbolPSymbolStep symbolStep = (SymbolPSymbolStep) step; - final Symbol target = symbolStep.getPSymbol().getSymbol(); - graph.connect(map.get(symbol.getId()), map.get(target.getId())); - - // fail fast if a symbol references itself - if (symbol.getId().equals(target.getId())) { - return true; - } - } - } - } - - final Set> computedSCCs = - SCCs.collectSCCs(graph).stream().map(HashSet::new).collect(Collectors.toSet()); - - return computedSCCs.stream() - .filter(s -> s.size() > 1) - .collect(Collectors.toSet()) - .size() > 0; // remove single component SCC - } - - public List hide(User user, Long projectId, List ids) { - final Project project = projectRepository.findById(projectId).orElse(null); - final List symbols = symbolRepository.findAllByIdIn(ids); - for (Symbol symbol : symbols) { - checkAccess(user, project, symbol); - checkRunningProcesses(user, project, symbol); - - // check symbol lock status - this.symbolPresenceService.checkSymbolLockStatus(projectId, symbol.getId(), user.getId()); - } - - for (Symbol symbol : symbols) { - symbol.setHidden(true); - - // rename the symbol so that there can be another new symbol with the name - final Timestamp timestamp = new Timestamp(System.currentTimeMillis()); - symbol.setName(symbol.getName() + "--" + DATE_FORMAT.format(timestamp)); - } - - final List archivedSymbols = symbolRepository.saveAll(symbols); - archivedSymbols.forEach(SymbolDAO::loadLazyRelations); - return archivedSymbols; - } - - public void show(User user, Long projectId, List ids) { - Project project = projectDAO.getByID(user, projectId); // access check - - // get symbols - List symbols = ids.stream().map(id -> this.get(user, project, id)).collect(Collectors.toList()); - - // check symbol lock status - symbols.forEach(symbol -> { - this.symbolPresenceService.checkSymbolLockStatus(projectId, symbol.getId(), user.getId()); - checkRunningProcesses(user, project, symbol); - }); - - symbols.forEach(symbol -> { - symbol.setHidden(false); - symbolRepository.save(symbol); - }); - } - - public void delete(User user, Long projectId, Long symbolId) { - final Symbol symbol = get(user, projectId, symbolId); - - // check symbol lock status - this.symbolPresenceService.checkSymbolLockStatusStrict(projectId, symbolId, user.getId()); - - if (!symbol.isHidden()) { - throw new ValidationException("Symbol has to be archived first."); - } - - long r1 = parameterizedSymbolRepository.countAllBySymbol_Id(symbolId); - long r2 = symbolPSymbolStepRepository.countAllBypSymbol_Symbol_Id(symbolId); - long r3 = testCaseStepRepository.countAllBypSymbol_Symbol_Id(symbolId); - long r4 = testExecutionResultRepository.countAllBySymbol_Id(symbolId); - - long refCount = r1 + r2 + r3 + r4; - if (refCount > 0) { - throw new ValidationException("There are " + refCount + " references to this symbol."); - } else { - symbolActionRepository.deleteAllBySymbol_Id(symbolId); - parameterizedSymbolRepository.deleteAll(symbol.getSteps().stream() - .filter(s -> s instanceof SymbolPSymbolStep) - .map(s -> ((SymbolPSymbolStep) s).getPSymbol()) - .collect(Collectors.toList())); - symbolRepository.deleteById(symbolId); - } - } - - public void delete(User user, Long projectId, List symbolIds) { - for (Long id : symbolIds) { - delete(user, projectId, id); - } - } - - /** - * Sets references to related entities to all actions of a symbol. - * - * @param symbol - * The symbol. - */ - public static void beforeSymbolSave(Symbol symbol) { - symbol.getInputs().forEach(i -> i.setSymbol(symbol)); - symbol.getOutputs().forEach(o -> o.setSymbol(symbol)); - } - - public void checkRunningProcesses(User user, Project project, Symbol symbol) { - if (this.getActiveSymbols(user, project).stream().anyMatch(s -> s.getId().equals(symbol.getId()))) { - throw new EntityLockedException("The symbol is currently used in the active test or learning process."); - } - } - - public Set getActiveSymbols(User user, Project project) { - Set result = new HashSet<>(); - - // check running tests, ignore testSuites - this.testDAO.getActiveTests(user, project).stream() - .filter(t -> t instanceof TestCase) - .flatMap(t -> Stream.of( - ((TestCase) t).getPreSteps(), - ((TestCase) t).getSteps(), - ((TestCase) t).getPostSteps())) - .flatMap(List::stream) - .map(TestCaseStep::getPSymbol) - .filter(Objects::nonNull) - .map(ParameterizedSymbol::getSymbol) - .forEach(result::add); - - // check running learning processes - this.learnerSetupDAO.getActiveLearnerSetups(user, project.getId()).forEach(learnerSetup -> { - List postSymbolSingletonList = Optional.ofNullable(learnerSetup.getPostSymbol()) - .map(List::of) - .orElse(Collections.emptyList()); - - Stream.of(List.of(learnerSetup.getPreSymbol()), postSymbolSingletonList, learnerSetup.getSymbols()) - .flatMap(List::stream) - .map(ParameterizedSymbol::getSymbol) - .forEach(result::add); - }); - - return result; - } - - /** - * Use Hibernate to populate all fields of a Symbol, including all references to other entities. - * - * @param symbol - * The Symbol to populate. - */ - public static void loadLazyRelations(Symbol symbol) { - Hibernate.initialize(symbol.getProject()); - Hibernate.initialize(symbol.getProject().getEnvironments()); - Hibernate.initialize(symbol.getGroup()); - Hibernate.initialize(symbol.getInputs()); - Hibernate.initialize(symbol.getOutputs()); - Hibernate.initialize(symbol.getSteps()); - symbol.getSteps().forEach(step -> { - if (step instanceof SymbolPSymbolStep) { - ParameterizedSymbolDAO.loadLazyRelations(((SymbolPSymbolStep) step).getPSymbol()); - } - }); - } - - public void checkAccess(User user, Project project, Symbol symbol) { - projectDAO.checkAccess(user, project); - - if (symbol == null) { - throw new NotFoundException("The symbol does not exist."); - } - - if (!symbol.getProject().equals(project)) { - throw new UnauthorizedException("You are not allowed to access the symbol."); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/dao/SymbolGroupDAO.java b/backend/src/main/java/de/learnlib/alex/data/dao/SymbolGroupDAO.java deleted file mode 100644 index 1b008f9db..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/dao/SymbolGroupDAO.java +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.dao; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.EntityLockedException; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolGroup; -import de.learnlib.alex.data.entities.SymbolPSymbolStep; -import de.learnlib.alex.data.entities.SymbolStep; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.data.repositories.SymbolGroupRepository; -import de.learnlib.alex.data.repositories.SymbolRepository; -import de.learnlib.alex.websocket.services.SymbolPresenceService; -import org.apache.commons.collections.BidiMap; -import org.apache.commons.collections.bidimap.DualHashBidiMap; -import org.apache.shiro.authz.UnauthorizedException; -import org.hibernate.Hibernate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.validation.ValidationException; -import java.sql.Timestamp; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * Implementation of a SymbolGroupDAO using Spring Data. - */ -@Service -@Transactional(rollbackFor = Exception.class) -public class SymbolGroupDAO { - - /** The format for archived symbols. */ - private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd-HH:mm:ss"); - - private final ProjectRepository projectRepository; - private final ProjectDAO projectDAO; - private final SymbolGroupRepository symbolGroupRepository; - private final SymbolRepository symbolRepository; - private final SymbolDAO symbolDAO; - private final SymbolPresenceService symbolPresenceService; - - @Autowired - public SymbolGroupDAO( - ProjectRepository projectRepository, - ProjectDAO projectDAO, - SymbolGroupRepository symbolGroupRepository, - SymbolRepository symbolRepository, - @Lazy SymbolDAO symbolDAO, - @Lazy SymbolPresenceService symbolPresenceService) { - this.projectRepository = projectRepository; - this.projectDAO = projectDAO; - this.symbolGroupRepository = symbolGroupRepository; - this.symbolRepository = symbolRepository; - this.symbolDAO = symbolDAO; - this.symbolPresenceService = symbolPresenceService; - } - - public List importGroups( - User user, - Project project, - List groups, - Map newSymbolIdToOldSymbolId - ) { - projectDAO.checkAccess(user, project); - - // name -> symbol - // save symbols steps - final Map> oldSymbolIdToStepsMap = new HashMap<>(); - groups.forEach(group -> group.walk(g -> null, s -> { - oldSymbolIdToStepsMap.put(s.getId(), s.getSteps()); - s.setSteps(new ArrayList<>()); - return null; - })); - - // create symbol groups and symbols without steps - // because one might reference names of symbols in steps that have not yet been created - final List importedGroups = importGroups(user, project, groups, null, newSymbolIdToOldSymbolId); - - // create symbol steps - final Map> symbolIdToStepsMap = new HashMap<>(); - final List symbols = symbolDAO.getAll(user, project.getId()).stream() - .filter(s -> oldSymbolIdToStepsMap.containsKey(newSymbolIdToOldSymbolId.get(s.getId()))) - .collect(Collectors.toList()); - - symbols.forEach(s -> symbolIdToStepsMap.put(s.getId(), oldSymbolIdToStepsMap.get(newSymbolIdToOldSymbolId.get(s.getId())))); - - // replace old symbol id in symbolSteps - final BidiMap oldSymbolIdToNewSymbolId = new DualHashBidiMap(newSymbolIdToOldSymbolId).inverseBidiMap(); - symbolIdToStepsMap.forEach((aLong, symbolSteps) -> { - symbolSteps.forEach(symbolStep -> { - if (symbolStep instanceof SymbolPSymbolStep) { - var newPSymbolId = (Long) oldSymbolIdToNewSymbolId.get(((SymbolPSymbolStep) symbolStep).getPSymbol().getSymbol().getId()); - ((SymbolPSymbolStep) symbolStep).getPSymbol().getSymbol().setId(newPSymbolId); - } - }); - }); - - symbolDAO.saveSymbolSteps(project.getId(), symbols, symbolIdToStepsMap); - - return importedGroups; - } - - private List importGroups( - User user, - Project project, - List groups, - SymbolGroup parent, - Map newSymbolIdToOldSymbolId - ) { - final List importedGroups = new ArrayList<>(); - for (SymbolGroup group : groups) { - final List children = group.getGroups(); - final Set symbols = group.getSymbols(); - - group.setGroups(new ArrayList<>()); - group.setSymbols(new HashSet<>()); - group.setProject(project); - group.setParent(parent); - group.setName(createGroupName(project, group)); - - beforePersistGroup(group); - final SymbolGroup createdGroup = symbolGroupRepository.save(group); - - symbols.forEach(symbol -> { - symbol.setProject(project); - symbol.setGroup(createdGroup); - }); - symbolDAO.importSymbols(user, project, new ArrayList<>(symbols), newSymbolIdToOldSymbolId); - - final var createdChildGroups = importGroups(user, project, children, createdGroup, newSymbolIdToOldSymbolId); - createdGroup.setGroups(createdChildGroups); - importedGroups.add(createdGroup); - } - return importedGroups; - } - - public SymbolGroup create(User user, Long projectId, SymbolGroup group) { - final Project project = projectRepository.findById(projectId).orElse(null); - projectDAO.checkAccess(user, project); - - group.setId(null); - group.setName(createGroupName(project, group)); - group.setProject(project); - project.addGroup(group); - beforePersistGroup(group); - - if (group.getParentId() != null) { - final SymbolGroup parent = symbolGroupRepository.findById(group.getParentId()).orElse(null); - checkAccess(user, project, parent); - - group.setParent(parent); - parent.getGroups().add(parent); - symbolGroupRepository.save(parent); - } - - return symbolGroupRepository.save(group); - } - - public List create(User user, Long projectId, List groups) { - final Project project = projectRepository.findById(projectId).orElse(null); - projectDAO.checkAccess(user, project); - - final List createdGroups = create(user, project, groups, null); - createdGroups.forEach(this::loadLazyRelations); - return groups; - } - - private List create(User user, Project project, List groups, SymbolGroup parent) { - final List createdGroups = new ArrayList<>(); - for (SymbolGroup group : groups) { - createdGroups.add(create(user, project, group, parent)); - } - return createdGroups; - } - - private SymbolGroup create(User user, Project project, SymbolGroup group, SymbolGroup parent) { - final List children = group.getGroups(); - final Set symbols = group.getSymbols(); - - group.setGroups(new ArrayList<>()); - group.setSymbols(new HashSet<>()); - group.setProject(project); - group.setParent(parent); - group.setName(createGroupName(project, group)); - - beforePersistGroup(group); - final SymbolGroup createdGroup = symbolGroupRepository.save(group); - - symbols.forEach(symbol -> { - symbol.setProject(project); - symbol.setGroup(createdGroup); - }); - symbolDAO.create(user, project.getId(), new ArrayList<>(symbols)); - - final List createdChildren = create(user, project, children, createdGroup); - createdGroup.setGroups(createdChildren); - return createdGroup; - } - - public List getAll(User user, long projectId) { - final Project project = projectRepository.findById(projectId).orElse(null); - projectDAO.checkAccess(user, project); - - final var groups = symbolGroupRepository.findAllByProject_IdAndParent_id(projectId, null); - for (SymbolGroup group : groups) { - loadLazyRelations(group); - } - - return groups; - } - - public SymbolGroup get(User user, long projectId, Long groupId) { - final Project project = projectRepository.findById(projectId).orElse(null); - final SymbolGroup group = symbolGroupRepository.findById(groupId).orElse(null); - checkAccess(user, project, group); - - loadLazyRelations(group); - - return group; - } - - public SymbolGroup update(User user, Long projectId, Long groupId, SymbolGroup group) { - final var project = projectRepository.findById(projectId).orElse(null); - final var groupInDB = symbolGroupRepository.findById(groupId).orElse(null); - checkAccess(user, project, groupInDB); - - // check group lock status - this.symbolPresenceService.checkGroupLockStatus(project.getId(), group.getId()); - - // has name changed? - if (!group.getName().equals(groupInDB.getName())) { - groupInDB.setName(createGroupName(project, group)); - } - - final var updatedGroup = symbolGroupRepository.save(groupInDB); - loadLazyRelations(updatedGroup); - - return updatedGroup; - } - - public SymbolGroup move(User user, SymbolGroup group) { - final Project project = projectRepository.findById(group.getProjectId()).orElse(null); - final SymbolGroup groupInDB = symbolGroupRepository.findById(group.getId()).orElse(null); - checkAccess(user, project, groupInDB); - - // check group lock status - this.symbolPresenceService.checkGroupLockStatus(project.getId(), group.getId()); - - final SymbolGroup defaultGroup = symbolGroupRepository.findFirstByProject_IdOrderByIdAsc(project.getId()); - if (defaultGroup.equals(groupInDB)) { - throw new ValidationException("You cannot move the default group."); - } - - if (group.getParent() != null && groupInDB.getId().equals(group.getParentId())) { - throw new ValidationException("A group cannot be a parent of itself."); - } - - final SymbolGroup movedGroup; - if (group.getParentId() == null) { - // move group to the upmost level - groupInDB.getParent().getGroups().remove(groupInDB); - symbolGroupRepository.save(groupInDB.getParent()); - group.setName(createGroupName(project, group)); - movedGroup = symbolGroupRepository.save(group); - } else { - final SymbolGroup newParent = symbolGroupRepository.findById(group.getParentId()).orElse(null); - checkAccess(user, project, newParent); - - // remove group from old parent - if (groupInDB.getParent() != null) { - if (newParent.isDescendantOf(groupInDB)) { - throw new ValidationException("A group cannot be moved to a child group."); - } - groupInDB.getParent().getGroups().remove(groupInDB); - symbolGroupRepository.save(groupInDB.getParent()); - } - - // add group to new parent - newParent.getGroups().add(groupInDB); - groupInDB.setParent(newParent); - symbolGroupRepository.save(newParent); - group.setName(createGroupName(project, group)); - movedGroup = symbolGroupRepository.save(groupInDB); - } - - loadLazyRelations(movedGroup); - return movedGroup; - } - - public void delete(User user, long projectId, Long groupId) { - final Project project = projectRepository.findById(projectId).orElse(null); - final SymbolGroup group = symbolGroupRepository.findById(groupId).orElse(null); - checkAccess(user, project, group); - checkRunningProcesses(user, project, group); - - // check symbolgroup lock status - this.symbolPresenceService.checkGroupLockStatus(projectId, groupId); - - final SymbolGroup defaultGroup = symbolGroupRepository.findFirstByProject_IdOrderByIdAsc(projectId); - if (defaultGroup.equals(group)) { - throw new IllegalArgumentException("You can not delete the default group of a project."); - } - - group.walk(g -> { - hideSymbols(g, defaultGroup); - return null; - }, s -> null); - - if (group.getParent() != null) { - group.getParent().getGroups().remove(group); - symbolGroupRepository.save(group.getParent()); - } - - group.setSymbols(null); - symbolGroupRepository.delete(group); - } - - private void hideSymbols(SymbolGroup group, SymbolGroup defaultGroup) { - for (Symbol symbol : group.getSymbols()) { - symbol.setGroup(defaultGroup); - symbol.setHidden(true); - final Timestamp timestamp = new Timestamp(System.currentTimeMillis()); - symbol.setName(symbol.getName() + "--" + DATE_FORMAT.format(timestamp)); - symbolRepository.save(symbol); - } - } - - public void checkAccess(User user, Project project, SymbolGroup group) { - projectDAO.checkAccess(user, project); - - if (group == null) { - throw new NotFoundException("The group could not be found."); - } - - if (!group.getProject().equals(project)) { - throw new UnauthorizedException("You are not allowed to access the group."); - } - } - - public void checkRunningProcesses(User user, Project project, SymbolGroup symbolGroup) { - if (this.getActiveSymbolGroups(user, project).stream().anyMatch(sg -> sg.getId().equals(symbolGroup.getId()))) { - throw new EntityLockedException("The SymbolGroup is currently used in the active test or learning process."); - } - } - - public Set getActiveSymbolGroups(User user, Project project) { - Set result = new HashSet<>(); - - this.symbolDAO.getActiveSymbols(user, project).forEach(s -> { - result.add(s.getGroup()); - result.addAll(extractAncestorSymbolGroups(s.getGroup())); - result.addAll(extractDescendantSymbolGroups(s.getGroup())); - }); - - return result; - } - - private Set extractDescendantSymbolGroups(SymbolGroup symbolGroup) { - Set result = new HashSet<>(); - - symbolGroup.getGroups().forEach(descendant -> { - result.add(descendant); - result.addAll(extractDescendantSymbolGroups(descendant)); - }); - - return result; - } - - public Set extractAncestorSymbolGroups(SymbolGroup symbolGroup) { - Set result = new HashSet<>(); - - Optional.ofNullable(symbolGroup.getParent()) - .ifPresent(ancestor -> { - result.add(ancestor); - result.addAll(extractAncestorSymbolGroups(ancestor)); - }); - - return result; - } - - private String createGroupName(Project project, SymbolGroup group) { - int i = 1; - String name = group.getName(); - while (symbolGroupRepository.findOneByProject_IdAndParent_IdAndName(project.getId(), group.getParentId(), name) != null) { - name = group.getName() + " (" + i + ")"; - i++; - } - return name; - } - - private void loadLazyRelations(SymbolGroup group) { - Hibernate.initialize(group.getGroups()); - Hibernate.initialize(group.getSymbols()); - group.getSymbols().forEach(SymbolDAO::loadLazyRelations); - - for (SymbolGroup g : group.getGroups()) { - loadLazyRelations(g); - } - } - - /** - * This method makes sure that all Symbols within the provided group will also be persisted. - * - * @param group - * The Group to take care of its Symbols. - */ - private void beforePersistGroup(SymbolGroup group) { - group.getSymbols().forEach(symbol -> { - group.getProject().addSymbol(symbol); - symbol.setGroup(group); - SymbolDAO.beforeSymbolSave(symbol); - }); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/dao/SymbolParameterDAO.java b/backend/src/main/java/de/learnlib/alex/data/dao/SymbolParameterDAO.java deleted file mode 100644 index 943fad945..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/dao/SymbolParameterDAO.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.dao; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolInputParameter; -import de.learnlib.alex.data.entities.SymbolOutputMapping; -import de.learnlib.alex.data.entities.SymbolOutputParameter; -import de.learnlib.alex.data.entities.SymbolParameter; -import de.learnlib.alex.data.entities.SymbolParameterValue; -import de.learnlib.alex.data.repositories.ParameterizedSymbolRepository; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.data.repositories.SymbolOutputMappingRepository; -import de.learnlib.alex.data.repositories.SymbolParameterRepository; -import de.learnlib.alex.data.repositories.SymbolParameterValueRepository; -import de.learnlib.alex.data.repositories.SymbolRepository; -import de.learnlib.alex.websocket.services.SymbolPresenceService; -import java.time.ZonedDateTime; -import java.util.List; -import javax.validation.ValidationException; -import org.apache.shiro.authz.UnauthorizedException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -/** The concrete DAO for symbol parameters. */ -@Service -@Transactional(rollbackFor = Exception.class) -public class SymbolParameterDAO { - - private final ProjectRepository projectRepository; - private final SymbolRepository symbolRepository; - private final SymbolParameterRepository symbolParameterRepository; - private final SymbolParameterValueRepository symbolParameterValueRepository; - private final ParameterizedSymbolRepository parameterizedSymbolRepository; - private final SymbolOutputMappingRepository outputMappingRepository; - private final SymbolPresenceService symbolPresenceService; - private final SymbolDAO symbolDAO; - - @Autowired - public SymbolParameterDAO(ProjectRepository projectRepository, - SymbolRepository symbolRepository, - SymbolParameterRepository symbolParameterRepository, - SymbolParameterValueRepository symbolParameterValueRepository, - ParameterizedSymbolRepository parameterizedSymbolRepository, - SymbolDAO symbolDAO, - SymbolOutputMappingRepository outputMappingRepository, - SymbolPresenceService symbolPresenceService) { - this.projectRepository = projectRepository; - this.symbolRepository = symbolRepository; - this.symbolParameterRepository = symbolParameterRepository; - this.symbolParameterValueRepository = symbolParameterValueRepository; - this.parameterizedSymbolRepository = parameterizedSymbolRepository; - this.symbolDAO = symbolDAO; - this.outputMappingRepository = outputMappingRepository; - this.symbolPresenceService = symbolPresenceService; - } - - public SymbolParameter create(User user, Long projectId, Long symbolId, SymbolParameter parameter) { - final Project project = projectRepository.findById(projectId).orElse(null); - final Symbol symbol = symbolRepository.findById(symbolId).orElse(null); - - return create(user, project, symbol, parameter); - } - - public SymbolParameter update(User user, Long projectId, Long symbolId, Long parameterId, SymbolParameter parameter) { - final var project = projectRepository.findById(projectId).orElse(null); - final var symbol = symbolRepository.findById(symbolId).orElse(null); - final var parameterInDB = symbolParameterRepository.findById(parameterId).orElse(null); - - checkAccess(user, project, symbol, parameterInDB); - checkIfTypeWithNameExists(symbol, parameter); - - // check symbol lock status - symbolPresenceService.checkSymbolLockStatus(project.getId(), symbol.getId(), user.getId()); - - symbol.setUpdatedOn(ZonedDateTime.now()); - symbolRepository.save(symbol); - - parameterInDB.setName(parameter.getName()); - parameterInDB.setParameterType(parameter.getParameterType()); - - return symbolParameterRepository.save(parameterInDB); - } - - public void delete(User user, Long projectId, Long symbolId, Long parameterId) { - final Project project = projectRepository.findById(projectId).orElse(null); - final Symbol symbol = symbolRepository.findById(symbolId).orElse(null); - final SymbolParameter parameter = symbolParameterRepository.findById(parameterId).orElse(null); - - checkAccess(user, project, symbol, parameter); - - // check symbol lock status - symbolPresenceService.checkSymbolLockStatus(project.getId(), symbol.getId(), user.getId()); - - final List pSymbols = parameterizedSymbolRepository.findAllBySymbol_Id(symbolId); - for (ParameterizedSymbol pSymbol : pSymbols) { - pSymbol.getParameterValues().removeIf(pv -> pv.getParameter().getId().equals(parameterId)); - pSymbol.getOutputMappings().removeIf(pv -> pv.getParameter().getId().equals(parameterId)); - } - parameterizedSymbolRepository.saveAll(pSymbols); - - // also delete all values for the parameter - symbolParameterValueRepository.removeAllByParameter_Id(parameterId); - outputMappingRepository.removeAllByParameter_Id(parameterId); - - symbol.removeParameter(parameter); - symbol.setUpdatedOn(ZonedDateTime.now()); - symbolRepository.save(symbol); - - symbolParameterRepository.deleteById(parameterId); - } - - public void checkAccess(User user, Project project, Symbol symbol, SymbolParameter parameter) { - symbolDAO.checkAccess(user, project, symbol); - - if (parameter == null) { - throw new NotFoundException("The parameter could not be found."); - } - - if (!symbol.containsParameter(parameter)) { - throw new UnauthorizedException("You are not allowed to access the parameter."); - } - } - - private SymbolParameter create(User user, Project project, Symbol symbol, SymbolParameter parameter) { - symbolDAO.checkAccess(user, project, symbol); - checkIfTypeWithNameExists(symbol, parameter); - - // check symbol lock status - symbolPresenceService.checkSymbolLockStatus(project.getId(), symbol.getId(), user.getId()); - - parameter.setSymbol(symbol); - symbol.addParameter(parameter); - - final SymbolParameter createdParameter = symbolParameterRepository.save(parameter); - symbol.setUpdatedOn(ZonedDateTime.now()); - symbolRepository.save(symbol); - - // If a new parameter is created for a symbol, it may be that there are tests that use the symbol. - // Therefore we have to add a new parameter value to the test steps that use the symbol. - final List pSymbols = parameterizedSymbolRepository.findAllBySymbol_Id(symbol.getId()); - if (parameter instanceof SymbolInputParameter) { - pSymbols.forEach(pSymbol -> { - final SymbolParameterValue value = new SymbolParameterValue(); - value.setParameter(parameter); - value.setDefaultValueByParameter(parameter); - pSymbol.getParameterValues().add(value); - symbolParameterValueRepository.saveAll(pSymbol.getParameterValues()); - }); - parameterizedSymbolRepository.saveAll(pSymbols); - } else if (parameter instanceof SymbolOutputParameter) { - pSymbols.forEach(pSymbol -> { - final SymbolOutputMapping om = new SymbolOutputMapping(); - om.setParameter(parameter); - om.setName(parameter.getName()); - pSymbol.getOutputMappings().add(om); - outputMappingRepository.saveAll(pSymbol.getOutputMappings()); - }); - } - - return createdParameter; - } - - private void checkIfTypeWithNameExists(Symbol symbol, SymbolParameter parameter) { - if (parameter instanceof SymbolInputParameter) { - if (typeWithNameExists(symbol.getInputs(), parameter)) { - throw new ValidationException("The name of the input parameter already exists."); - } - } else if (parameter instanceof SymbolOutputParameter) { - if (typeWithNameExists(symbol.getOutputs(), parameter)) { - throw new ValidationException("The name of the output parameter already exists."); - } - } - } - - private boolean typeWithNameExists(List parameters, SymbolParameter parameter) { - return parameters.stream().anyMatch(p -> - p.getName().equals(parameter.getName()) && !p.getId().equals(parameter.getId()) - ); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/BaseEntity.java b/backend/src/main/java/de/learnlib/alex/data/entities/BaseEntity.java deleted file mode 100644 index 94de96af6..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/BaseEntity.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.vladmihalcea.hibernate.type.array.ListArrayType; -import javax.persistence.MappedSuperclass; -import org.hibernate.annotations.TypeDef; -import org.hibernate.annotations.TypeDefs; - -@MappedSuperclass -@TypeDefs({ - @TypeDef(name = "list-array", typeClass = ListArrayType.class) -}) -public class BaseEntity { -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/Counter.java b/backend/src/main/java/de/learnlib/alex/data/entities/Counter.java deleted file mode 100644 index 5ac840cb9..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/Counter.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import java.io.Serializable; -import java.util.Objects; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.ManyToOne; -import javax.persistence.Table; -import javax.persistence.UniqueConstraint; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; - -/** - * A simple counter class. - */ -@Entity -@Table( - uniqueConstraints = @UniqueConstraint(columnNames = {"project_id", "name"}) -) -@JsonPropertyOrder(alphabetic = true) -public class Counter implements Serializable { - - private static final long serialVersionUID = 5495935413098569457L; - - /** The ID of the counter in the DB. */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - /** The project the counter belongs to. */ - @ManyToOne(fetch = FetchType.EAGER, optional = false) - @JsonIgnore - private Project project; - - /** The name of the counter. */ - @NotBlank - @Pattern(regexp = "[a-zA-Z0-9]+[a-zA-Z0-9\\-_]*") - private String name; - - /** The value of the counter. */ - @NotNull - private Integer value; - - public Counter() { - value = 0; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Project getProject() { - return project; - } - - public void setProject(Project project) { - this.project = project; - } - - /** - * Get the ID of {@link Project} the Symbol belongs to. - * - * @return The parent Project. - */ - @JsonProperty("project") - public Long getProjectId() { - return project == null ? null : project.getId(); - } - - /** - * Set the ID of the {@link Project} the Symbol belongs to. - * - * @param projectId - * The new parent Project. - */ - @JsonProperty("project") - public void setProjectId(Long projectId) { - this.project = new Project(projectId); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Integer getValue() { - return value; - } - - public void setValue(Integer value) { - this.value = value < 0 ? 0 : value; - } - - //CHECKSTYLE.OFF: AvoidInlineConditionals|MagicNumber - auto generated by IntelliJ IDEA - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof Counter)) { - return false; - } - - Counter counter = (Counter) o; - - if (!Objects.equals(project, counter.project)) { - return false; - } - return Objects.equals(name, counter.name); - } - - @Override - public int hashCode() { - int result = project != null ? project.hashCode() : 0; - result = 31 * result + (name != null ? name.hashCode() : 0); - return result; - } - // CHECKSTYLE.OFF: AvoidInlineConditionals|MagicNumber -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/CreateProjectForm.java b/backend/src/main/java/de/learnlib/alex/data/entities/CreateProjectForm.java deleted file mode 100644 index 62e192e64..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/CreateProjectForm.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import static de.learnlib.alex.data.entities.Project.MAX_DESCRIPTION_LENGTH; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Pattern; -import org.hibernate.validator.constraints.Length; - -public class CreateProjectForm { - - @NotBlank - private String name; - - @Length(max = MAX_DESCRIPTION_LENGTH) - private String description; - - @NotBlank - @Pattern(regexp = "^https?://.*?") - private String url; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/ExecuteResult.java b/backend/src/main/java/de/learnlib/alex/data/entities/ExecuteResult.java deleted file mode 100644 index 2f2d8cf28..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/ExecuteResult.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import de.learnlib.alex.testing.entities.TestScreenshot; -import java.io.Serializable; -import java.util.StringJoiner; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.OneToOne; -import javax.persistence.Transient; - -/** Class to determine if a symbol has been executed successfully. */ -@Entity -public class ExecuteResult implements Serializable { - - private static final long serialVersionUID = -4296479981133118914L; - - /** The default output on success. */ - public static final String DEFAULT_SUCCESS_OUTPUT = "Ok"; - - /** The default output on error. */ - public static final String DEFAULT_ERROR_OUTPUT = "Failed"; - - /** The id of the execute result in the db. */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @JsonIgnore - private Long id; - - /** If the symbol has been execute successfully. */ - private boolean success; - - /** The output of the SUL. */ - private String message; - - @Column(columnDefinition = "TEXT") - private String trace; - - /** The time in ms it took to execute the step. */ - private Long time; - - @OneToOne( - cascade = {CascadeType.ALL} - ) - private TestScreenshot testScreenshot; - - /** Constructor. */ - public ExecuteResult() { - this(true); - } - - public ExecuteResult(boolean success) { - this(success, null); - } - - public ExecuteResult(boolean success, String message) { - this(success, message, 0L); - } - - public ExecuteResult(boolean success, String message, Long time) { - this(success, message, "", time, null); - } - - public ExecuteResult(boolean success, String message, String trace, Long time, TestScreenshot testScreenshot) { - this.success = success; - this.message = message; - this.time = time; - this.trace = trace; - this.testScreenshot = testScreenshot; - } - - public void addTrace(Symbol symbol, ExecuteResult result) { - if (!trace.equals("")) { - trace = " > " + trace; - } - trace = "[" + symbol.getName() + " / " + result.getOutput() + "]" + trace; - } - - public boolean isSuccess() { - return success; - } - - public void setSuccess(boolean success) { - this.success = success; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - @Transient - @JsonProperty("output") - public String getOutput() { - if (success) { - return DEFAULT_SUCCESS_OUTPUT + (message == null ? "" : " (" + message + ")"); - } else { - return DEFAULT_ERROR_OUTPUT + (message == null ? "" : " (" + message + ")"); - } - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Long getTime() { - return time; - } - - public void setTime(Long time) { - this.time = time; - } - - public String getTrace() { - return trace; - } - - public void setTrace(String trace) { - this.trace = trace; - } - - /** Negate the result. */ - public void negate() { - this.success = !this.success; - } - - @Override - public String toString() { - return new StringJoiner(", ", this.getClass().getSimpleName() + "[", "]") - .add("success = " + success) - .add("output = " + getOutput()) - .toString(); - } - - public TestScreenshot getTestScreenshot() { - return testScreenshot; - } - - public void setTestScreenshot(TestScreenshot testScreenshot) { - this.testScreenshot = testScreenshot; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/OutputsJob.java b/backend/src/main/java/de/learnlib/alex/data/entities/OutputsJob.java deleted file mode 100644 index b3148dd7f..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/OutputsJob.java +++ /dev/null @@ -1,81 +0,0 @@ -package de.learnlib.alex.data.entities; - -import java.time.Instant; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.List; - -public class OutputsJob { - public String id; - public boolean success; - public String message; - public Long projectId; - public Long environmentId; - public List outputs = new ArrayList<>(); - public ZonedDateTime startedAt; - public ZonedDateTime finishedAt; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public boolean isSuccess() { - return success; - } - - public void setSuccess(boolean success) { - this.success = success; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - public Long getProjectId() { - return projectId; - } - - public void setProjectId(Long projectId) { - this.projectId = projectId; - } - - public Long getEnvironmentId() { - return environmentId; - } - - public void setEnvironmentId(Long environmentId) { - this.environmentId = environmentId; - } - - public List getOutputs() { - return outputs; - } - - public void setOutputs(List outputs) { - this.outputs = outputs; - } - - public ZonedDateTime getStartedAt() { - return startedAt; - } - - public void setStartedAt(ZonedDateTime startedAt) { - this.startedAt = startedAt; - } - - public ZonedDateTime getFinishedAt() { - return finishedAt; - } - - public void setFinishedAt(ZonedDateTime finishedAt) { - this.finishedAt = finishedAt; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/ParameterizedSymbol.java b/backend/src/main/java/de/learnlib/alex/data/entities/ParameterizedSymbol.java deleted file mode 100644 index 22e3063cf..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/ParameterizedSymbol.java +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import de.learnlib.alex.common.utils.SearchHelper; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.CounterStoreConnector; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.api.exception.SULException; -import de.learnlib.mapper.api.ContextExecutableInput; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import javax.persistence.CascadeType; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; - -/** - * Symbol that is executed on the SUL that uses parameters. A symbol will then be used displayed as e.g. "NAME <value1, - * value2>" where "value1" and "value2" are values for the parameters. This way, a symbol can be used in multiple - * configurations during a learning process. - */ -@Entity -public class ParameterizedSymbol implements ContextExecutableInput, Serializable { - - private static final long serialVersionUID = -87489928962763046L; - - /** - * The ID of the parameterized symbol in the database. - */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - /** - * The symbol to execute. - */ - @OneToOne( - fetch = FetchType.EAGER - ) - private Symbol symbol; - - private String alias; - - /** - * The parameter values for the symbol to execute. - */ - @OneToMany( - fetch = FetchType.EAGER, - cascade = {CascadeType.PERSIST, CascadeType.REMOVE} - ) - private List parameterValues; - - /** - * The parameter values for the symbol to execute. - */ - @OneToMany( - fetch = FetchType.LAZY, - cascade = {CascadeType.PERSIST, CascadeType.REMOVE} - ) - private List outputMappings; - - /** - * Constructor. - */ - public ParameterizedSymbol() { - this.parameterValues = new ArrayList<>(); - this.outputMappings = new ArrayList<>(); - } - - /** - * Constructor. - * - * @param symbol - * The symbol to execute. - */ - public ParameterizedSymbol(Symbol symbol) { - this(); - this.symbol = symbol; - } - - private boolean allInputValuesDefined() { - return parameterValues.isEmpty() || parameterValues.stream().allMatch(pv -> pv.getValue() != null); - } - - @Override - public ExecuteResult execute(ConnectorManager connectors) throws SULException { - if (!allInputValuesDefined()) { - return new ExecuteResult(false, "Undefined input value"); - } - - // global scope - final VariableStoreConnector variableStore = connectors.getConnector(VariableStoreConnector.class); - final CounterStoreConnector counterStore = connectors.getConnector(CounterStoreConnector.class); - - // local scope - final VariableStoreConnector localVariableStore = new VariableStoreConnector(); - final CounterStoreConnector localCounterStore = counterStore.clone(); - - // user defined values for parameters (name -> value) - final Map pvMap = new HashMap<>(); - parameterValues.forEach(pv -> pvMap.put(pv.getParameter().getName(), pv.getValue())); - - // set values in local scope - try { - for (final SymbolInputParameter in : symbol.getInputs()) { - if (in.getParameterType().equals(SymbolParameter.ParameterType.STRING)) { - final var userValue = pvMap.get(in.getName()); - final var variableValue = SearchHelper.insertVariableValues( - connectors, - symbol.getProjectId(), - userValue - ); - localVariableStore.set(in.getName(), variableValue); - } else { - localCounterStore.set(symbol.getProjectId(), in.getName(), counterStore.get(in.getName())); - } - } - } catch (IllegalStateException e) { - return new ExecuteResult(false, e.getMessage()); - } - - connectors.addConnector(localVariableStore); - connectors.addConnector(localCounterStore); - - final ExecuteResult result = symbol.execute(connectors); - - // update global scope - try { - for (final SymbolOutputParameter out : symbol.getOutputs()) { - if (out.getParameterType().equals(SymbolParameter.ParameterType.STRING) && result.isSuccess()) { - final SymbolOutputMapping outputMapping = getOutputMappingFor(out.getName()); - variableStore.set(outputMapping.getName(), localVariableStore.get(out.getName())); - } else if (out.getParameterType().equals(SymbolParameter.ParameterType.COUNTER)) { - counterStore.set(symbol.getProjectId(), out.getName(), localCounterStore.get(out.getName())); - } - } - } catch (IllegalStateException e) { - return new ExecuteResult(false, e.getMessage()); - } - - connectors.addConnector(variableStore); - connectors.addConnector(counterStore); - - return result; - } - - private SymbolOutputMapping getOutputMappingFor(String name) { - for (SymbolOutputMapping m : outputMappings) { - if (m.getParameter().getName().equals(name)) { - return m; - } - } - throw new IllegalStateException("No mapping for " + name + " found"); - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Symbol getSymbol() { - return symbol; - } - - public void setSymbol(Symbol symbol) { - this.symbol = symbol; - } - - public List getParameterValues() { - return parameterValues; - } - - public void setParameterValues(List parameterValues) { - this.parameterValues = parameterValues; - } - - public List getOutputMappings() { - return outputMappings; - } - - public void setOutputMappings(List outputMappings) { - this.outputMappings = outputMappings; - } - - public String getAlias() { - return alias; - } - - public void setAlias(String alias) { - if (alias == null || alias.trim().equals("")) { - this.alias = null; - } else { - this.alias = alias; - } - } - - /** - * If there are no parameter values defined, the name will be "NAME". Otherwise it will be - * "NAME <value1, value2>" where "value1" and "value2" are concrete values for the parameters. - * - * @return The computed name based on the parameters. - */ - @JsonIgnore - public String getAliasOrComputedName() { - if (alias != null && !alias.equals("")) { - return alias; - } else { - return getComputedName(); - } - } - - @JsonIgnore - public String getComputedName() { - var parameters = getParameterList(); - if (parameters.isEmpty()) { - return getSymbol().getName(); - } else { - return getSymbol().getName() + " <" + String.join(", ", parameters) + ">"; - } - } - - @JsonIgnore - public String getAliasOrIdBasedName() { - if (alias != null && !alias.equals("")) { - return alias; - } else { - return getIdBasedName(); - } - } - - @JsonIgnore - public String getIdBasedName() { - var parameters = getParameterList(); - if (parameters.isEmpty()) { - return getSymbol().getId().toString(); - } else { - return getSymbol().getId().toString() + " <" + String.join(", ", parameters) + ">"; - } - } - - private List getParameterList() { - return parameterValues.stream() - .filter(pv -> pv.getValue() != null) - .map(SymbolParameterValue::getValue) - .collect(Collectors.toList()); - } - - /** - * Copies the parameterized symbol. There are new instances created that do not contain IDs so that the copy can be - * saved directly in the database. - * - * @return The copied parameterized symbol. - */ - public ParameterizedSymbol copy() { - final ParameterizedSymbol pSymbol = new ParameterizedSymbol(); - pSymbol.setSymbol(symbol); - pSymbol.setAlias(alias); - pSymbol.setOutputMappings( - outputMappings.stream().map(om -> { - final SymbolOutputMapping mapping = new SymbolOutputMapping(); - mapping.setParameter(om.getParameter()); - mapping.setName(om.getName()); - return mapping; - }).collect(Collectors.toList()) - ); - pSymbol.setParameterValues( - parameterValues.stream().map(pv -> { - final SymbolParameterValue value = new SymbolParameterValue(); - value.setParameter(pv.getParameter()); - value.setValue(pv.getValue()); - return value; - }).collect(Collectors.toList()) - ); - return pSymbol; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/Project.java b/backend/src/main/java/de/learnlib/alex/data/entities/Project.java deleted file mode 100644 index cfde7f380..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/Project.java +++ /dev/null @@ -1,528 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.learning.entities.LearnerSetup; -import de.learnlib.alex.modelchecking.entities.LtsFormulaSuite; -import de.learnlib.alex.testing.entities.Test; -import de.learnlib.alex.testing.entities.TestExecutionConfig; -import de.learnlib.alex.testing.entities.TestReport; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; -import javax.persistence.CascadeType; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.OneToMany; -import javax.persistence.Transient; -import javax.validation.constraints.NotBlank; -import org.hibernate.validator.constraints.Length; - -/** - * Representation of a testing project with different symbols. - */ -@Entity -@JsonInclude(JsonInclude.Include.NON_NULL) -public class Project implements Serializable { - - private static final long serialVersionUID = -6760395646972200067L; - - /** The maximum length for the project description. */ - public static final int MAX_DESCRIPTION_LENGTH = 250; - - /** - * The project ID. - */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - /** - * The list of users who are owners of the project. - */ - @ManyToMany( - cascade = {CascadeType.PERSIST, CascadeType.MERGE} - ) - @JoinTable( - name = "project_owners", - joinColumns = @JoinColumn(name = "project_id", referencedColumnName = "id"), - inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id") - ) - private List owners; - - /** - * The list of users who are members of the project. - */ - @ManyToMany( - cascade = {CascadeType.PERSIST, CascadeType.MERGE} - ) - @JoinTable( - name = "project_members", - joinColumns = @JoinColumn(name = "project_id", referencedColumnName = "id"), - inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id") - ) - private List members; - - /** - * The name of the project. This property is required & must be unique. - */ - @NotBlank - private String name; - - /** - * A text to describe the Project. - */ - @Length(max = MAX_DESCRIPTION_LENGTH) - private String description; - - /** - * The list of groups in the project. - */ - @OneToMany( - mappedBy = "project", - cascade = {CascadeType.ALL}, - orphanRemoval = true - ) - @JsonIgnore - private Set groups; - - @OneToMany( - mappedBy = "project", - cascade = {CascadeType.ALL}, - orphanRemoval = true - ) - private List environments; - - /** - * The list of test reports in the project. - */ - @OneToMany( - mappedBy = "project", - cascade = {CascadeType.ALL}, - orphanRemoval = true - ) - @JsonIgnore - private Set testReports; - - /** - * The symbols used to test. - */ - @OneToMany( - mappedBy = "project", - cascade = {CascadeType.ALL}, - orphanRemoval = true - ) - @JsonIgnore - private Set symbols; - - /** The tests of this project. */ - @OneToMany( - mappedBy = "project", - cascade = {CascadeType.ALL}, - orphanRemoval = true - ) - @JsonIgnore - private Set tests; - - /** The test configurations of this project. */ - @OneToMany( - mappedBy = "project", - cascade = {CascadeType.ALL}, - orphanRemoval = true - ) - @JsonIgnore - private List testExecutionConfigs; - - /** - * The counters of the project. - */ - @OneToMany( - mappedBy = "project", - cascade = {CascadeType.ALL}, - orphanRemoval = true - ) - @JsonIgnore - private Set counters; - - /** - * The counters of the project. - */ - @OneToMany( - mappedBy = "project", - cascade = {CascadeType.ALL}, - orphanRemoval = true - ) - @JsonIgnore - private List learnerResults; - - /** - * The counters of the project. - */ - @OneToMany( - mappedBy = "project", - cascade = {CascadeType.ALL}, - orphanRemoval = true - ) - @JsonIgnore - private List learnerSetups; - - /** - * The lts formulas of the project. - */ - @OneToMany( - mappedBy = "project", - cascade = {CascadeType.ALL}, - orphanRemoval = true - ) - @JsonIgnore - private List ltsFormulaSuites; - - /** - * Default constructor. - */ - public Project() { - this(0L); - } - - /** - * Constructor which set the ID. - * - * @param projectId - * The ID. - */ - - public Project(Long projectId) { - this.id = projectId; - this.groups = new HashSet<>(); - this.symbols = new HashSet<>(); - this.tests = new HashSet<>(); - this.testReports = new HashSet<>(); - this.testExecutionConfigs = new ArrayList<>(); - this.ltsFormulaSuites = new ArrayList<>(); - this.environments = new ArrayList<>(); - this.owners = new ArrayList<>(); - this.members = new ArrayList<>(); - this.learnerResults = new ArrayList<>(); - this.learnerSetups = new ArrayList<>(); - } - - /** - * Get the ID of the project. - * - * @return The ID. - */ - public Long getId() { - return id; - } - - /** - * Set the ID of this project. - * - * @param id - * The new ID. - */ - public void setId(Long id) { - this.id = id; - } - - /** - * Get the owners of the project. - * - * @return The list of owners of the project. - */ - @JsonIgnore - public List getOwners() { - return owners; - } - - /** - * Add an user as an owner to the project. - * - * @param owner - * The user who will be added as an owner. - */ - @JsonIgnore - public void addOwner(User owner) { - owners.add(owner); - } - - /** - * Set a list of users as the owners of the project. - * - * @param owners - * The new list of owners. - */ - @JsonIgnore - public void setOwners(List owners) { - if (owners != null) { - this.owners = owners; - } - } - - /** - * Remove an owner from the project. - * - * @param owner - * The user user who will be removed from the list of owners. - * @return True if the user was successfully removed - */ - @JsonIgnore - public boolean removeOwner(User owner) { - return owners.remove(owner); - } - - @JsonIgnore - public List getMembers() { - return members; - } - - @JsonIgnore - public void addMember(User member) { - members.add(member); - } - - @JsonIgnore - public void setMembers(List members) { - if (members != null) { - this.members = members; - } - } - - @JsonIgnore - public boolean removeMember(User member) { - return members.remove(member); - } - - @JsonProperty("members") - public List getMemberIds() { - return this.members.stream().map(User::getId).collect(Collectors.toList()); - } - - @JsonProperty("owners") - public List getOwnerIds() { - return this.owners.stream().map(User::getId).collect(Collectors.toList()); - } - - /** - * Get the name of this project. - * - * @return The name. - */ - public String getName() { - return name; - } - - /** - * Set a new name for the project. The name must be there and be unique. - * - * @param name - * The new name. - */ - public void setName(String name) { - this.name = name; - } - - /** - * Get the description of the Project. - * - * @return The Project description. - */ - public String getDescription() { - return description; - } - - /** - * Set the description of this project. - * - * @param description - * The new description. - */ - public void setDescription(String description) { - this.description = description; - } - - /** - * Get the groups of the project. - * - * @return The related groups. - */ - public Set getGroups() { - return groups; - } - - /** - * Set a new set of groups that are used in the project. - * - * @param groups - * The new set of groups. - */ - public void setGroups(Set groups) { - this.groups = groups; - } - - /** - * Add one group to the project. - * - * @param group - * The group to add. - */ - public void addGroup(SymbolGroup group) { - this.groups.add(group); - group.setProject(this); - } - - @JsonIgnore - public Collection getSymbols() { - return symbols; - } - - @JsonIgnore - public void setSymbols(Set symbols) { - this.symbols = symbols; - } - - public List getEnvironments() { - return environments; - } - - public void setEnvironments(List environments) { - this.environments = environments; - } - - /** - * Add a Symbol to the Project and set the Project in the Symbol. - * This only establishes the bidirectional relation does nothing else, - * e.g. it does not take care of the right id. - * - * @param symbol - * The Symbol to add. - */ - public void addSymbol(Symbol symbol) { - this.symbols.add(symbol); - symbol.setProject(this); - } - - @JsonIgnore - public Collection getTests() { - return tests; - } - - @JsonIgnore - public void setTests(Set tests) { - this.tests = tests; - } - - @JsonIgnore - public Set getTestReports() { - return testReports; - } - - @JsonIgnore - public void setTestReports(Set testReports) { - this.testReports = testReports; - } - - @JsonProperty - @JsonIgnore - public Set getCounters() { - return counters; - } - - @JsonIgnore - public void setCounters(Set counters) { - this.counters = counters; - } - - public List getLtsFormulaSuites() { - return ltsFormulaSuites; - } - - public void setLtsFormulaSuites(List ltsFormulaSuites) { - this.ltsFormulaSuites = ltsFormulaSuites; - } - - public List getTestExecutionConfigs() { - return testExecutionConfigs; - } - - public void setTestExecutionConfigs(List testExecutionConfigs) { - this.testExecutionConfigs = testExecutionConfigs; - } - - public List getLearnerResults() { - return learnerResults; - } - - public void setLearnerResults(List learnerResults) { - this.learnerResults = learnerResults; - } - - public List getLearnerSetups() { - return learnerSetups; - } - - public void setLearnerSetups(List learnerSetups) { - this.learnerSetups = learnerSetups; - } - - @Transient - @JsonIgnore - public ProjectEnvironment getDefaultEnvironment() { - return this.environments.stream() - .filter(ProjectEnvironment::isDefault) - .findFirst() - .orElse(null); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Project project = (Project) o; - return Objects.equals(id, project.id); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } - - @Override - public String toString() { - return "[Project " + id + "]: " /* + user */ + ", " + name; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/ProjectEnvironment.java b/backend/src/main/java/de/learnlib/alex/data/entities/ProjectEnvironment.java deleted file mode 100644 index 187f4ae14..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/ProjectEnvironment.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import javax.persistence.CascadeType; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Transient; -import javax.persistence.UniqueConstraint; -import javax.validation.constraints.NotEmpty; - -@Entity -@Table( - uniqueConstraints = @UniqueConstraint(columnNames = {"project_id", "name"}) -) -public class ProjectEnvironment implements Serializable { - - private static final long serialVersionUID = -1700444925209588234L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @NotEmpty - private String name; - - @ManyToOne(fetch = FetchType.EAGER, optional = false) - @JsonIgnore - private Project project; - - @OneToMany( - mappedBy = "environment", - cascade = CascadeType.ALL - ) - private List urls; - - @OneToMany( - mappedBy = "environment", - cascade = CascadeType.ALL - ) - private List variables; - - private boolean isDefault; - - public ProjectEnvironment() { - this.urls = new ArrayList<>(); - this.variables = new ArrayList<>(); - } - - @Transient - @JsonIgnore - public ProjectUrl getDefaultUrl() { - return this.urls.stream() - .filter(ProjectUrl::isDefault) - .findFirst() - .orElse(null); - } - - @Transient - @JsonIgnore - public Map getUrlsAsMap() { - return this.urls.stream().collect(Collectors.toMap(ProjectUrl::getName, ProjectUrl::getUrl)); - } - - @Transient - @JsonIgnore - public Map getVariablesAsMap() { - return this.variables.stream() - .collect(Collectors.toMap(ProjectEnvironmentVariable::getName, ProjectEnvironmentVariable::getValue)); - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Project getProject() { - return project; - } - - public void setProject(Project project) { - this.project = project; - } - - public boolean isDefault() { - return isDefault; - } - - public void setDefault(boolean aDefault) { - isDefault = aDefault; - } - - @JsonProperty("project") - public Long getProjectId() { - return project == null ? null : project.getId(); - } - - @JsonProperty("project") - public void setProjectId(Long projectId) { - this.project = new Project(projectId); - } - - public List getUrls() { - return urls; - } - - public void setUrls(List urls) { - this.urls = urls; - } - - public List getVariables() { - return variables; - } - - public void setVariables(List variables) { - this.variables = variables; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/ProjectEnvironmentVariable.java b/backend/src/main/java/de/learnlib/alex/data/entities/ProjectEnvironmentVariable.java deleted file mode 100644 index 3e3f51e98..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/ProjectEnvironmentVariable.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.io.Serializable; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.validation.constraints.NotBlank; - -@Entity -public class ProjectEnvironmentVariable implements Serializable { - - private static final long serialVersionUID = -2041972735097937620L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @ManyToOne(fetch = FetchType.EAGER, optional = false) - @JoinColumn(name = "environment_id") - @JsonIgnore - private ProjectEnvironment environment; - - @NotBlank - private String name; - - @NotBlank - private String value; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public ProjectEnvironment getEnvironment() { - return environment; - } - - public void setEnvironment(ProjectEnvironment environment) { - this.environment = environment; - } - - @JsonProperty("environment") - public Long getEnvironmentId() { - return environment != null ? environment.getId() : null; - } - - @JsonProperty("environment") - public void setEnvironmentId(Long envId) { - this.environment = new ProjectEnvironment(); - this.environment.setId(envId); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/ProjectUrl.java b/backend/src/main/java/de/learnlib/alex/data/entities/ProjectUrl.java deleted file mode 100644 index 17e119851..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/ProjectUrl.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.io.Serializable; -import java.util.Objects; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Pattern; - -/** The class for the URL of a target system. */ -@Entity -public class ProjectUrl implements Serializable { - - private static final long serialVersionUID = 2091513737646022637L; - - /** The id in the db. */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - /** The project the URL belongs to. */ - @ManyToOne(fetch = FetchType.EAGER, optional = false) - @JoinColumn(name = "environment_id") - @JsonIgnore - private ProjectEnvironment environment; - - /** An optional name for the URL. */ - private String name; - - /** The URL where the system is accessible. */ - @NotBlank - @Pattern(regexp = "^https?://.*?") - private String url; - - private boolean isDefault; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public ProjectEnvironment getEnvironment() { - return environment; - } - - public void setEnvironment(ProjectEnvironment environment) { - this.environment = environment; - } - - @JsonProperty("environment") - public Long getEnvironmentId() { - return environment == null ? null : environment.getId(); - } - - @JsonProperty("environment") - public void setEnvironmentId(Long environmentId) { - this.environment = new ProjectEnvironment(); - this.environment.setId(environmentId); - } - - public boolean isDefault() { - return isDefault; - } - - public void setDefault(boolean aDefault) { - isDefault = aDefault; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof ProjectUrl)) { - return false; - } - ProjectUrl that = (ProjectUrl) o; - return Objects.equals(getId(), that.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(getId()); - } - - @Override - public String toString() { - return "ProjectUrl{" - + "id=" + id - + ", name='" + name + '\'' - + ", url='" + url + '\'' - + '}'; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/Symbol.java b/backend/src/main/java/de/learnlib/alex/data/entities/Symbol.java deleted file mode 100644 index ec6243106..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/Symbol.java +++ /dev/null @@ -1,541 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.Constants; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.common.utils.SearchHelper; -import de.learnlib.alex.data.entities.actions.misc.CreateLabelAction; -import de.learnlib.alex.data.entities.actions.misc.JumpToLabelAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.api.exception.SULException; -import de.learnlib.mapper.api.ContextExecutableInput; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.OrderBy; -import javax.persistence.Transient; -import javax.validation.constraints.NotBlank; -import java.io.Serializable; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -/** - * Representation of a symbol for the learning process. A Symbol is one unit which will be executed and it is made of a - * sequence of actions. - */ -@Entity -@JsonPropertyOrder(alphabetic = true) -public class Symbol implements ContextExecutableInput, Serializable { - - private static final long serialVersionUID = 7987585761829495962L; - - private static final Logger logger = LoggerFactory.getLogger(Symbol.class); - - /** The id of the symbol in the project. */ - private Long id; - - /** The Project the Symbol belongs to. */ - private Project project; - - /** The group the symbol belongs to. */ - private SymbolGroup group; - - /** The name of the symbol. */ - private String name; - - /** The description of the symbol. */ - private String description; - - /** Description of what should be the state after the symbol has been executed. */ - private String expectedResult; - - /** flag to mark a symbol as hidden. readonly. */ - private boolean hidden; - - /** The steps to execute when the symbol is executed. */ - @OrderBy - private List steps; - - /** The custom output if the symbol is executed successfully. */ - private String successOutput; - - /** The list of input variables. */ - private List inputs; - - /** The list of output variables. */ - private List outputs; - - /** The date when the symbol was updated the last time. */ - @JsonIgnore - private ZonedDateTime updatedOn; - - /** The last user who modified the symbol. */ - private User lastUpdatedBy; - - /** Constructor. */ - public Symbol() { - this.inputs = new ArrayList<>(); - this.outputs = new ArrayList<>(); - this.steps = new ArrayList<>(); - this.expectedResult = ""; - this.description = ""; - this.hidden = false; - this.updatedOn = ZonedDateTime.now(); - this.lastUpdatedBy = null; - } - - /** - * Get the project the symbol belongs to. - * - * @return The (parent) project. - */ - @ManyToOne(fetch = FetchType.EAGER, optional = false) - @JoinColumn(name = "projectId") - @JsonIgnore - public Project getProject() { - return project; - } - - /** - * Set the project the symbol belongs to. - * - * @param project - * The new project. - */ - @JsonIgnore - public void setProject(Project project) { - this.project = project; - } - - /** - * Get the {@link Project} the Symbol belongs to. - * - * @return The parent Project. - */ - @Transient - @JsonProperty("project") - public Long getProjectId() { - return project == null ? null : project.getId(); - } - - /** - * Set the {@link Project} the Symbol belongs to. - * - * @param projectId - * The new parent Project. - */ - @JsonProperty("project") - public void setProjectId(Long projectId) { - this.project = new Project(projectId); - } - - /** - * Get related group of the symbol. - * - * @return The group the symbols is a part of. - */ - @ManyToOne(fetch = FetchType.EAGER, optional = false) - @JoinColumn(name = "groupId") - @JsonIgnore - public SymbolGroup getGroup() { - return group; - } - - /** - * Set the group of the symbol. - * - * @param group - * The new group the symbols should be part of. - */ - @JsonIgnore - public void setGroup(SymbolGroup group) { - this.group = group; - } - - /** - * Get the ID of the related group. - * - * @return The ID of the group the symbol belongs to or 0L. - */ - @Transient - @JsonProperty("group") - public Long getGroupId() { - return group == null ? null : group.getId(); - } - - /** - * Set the ID of the related group. - * - * @param groupId - * The new group ID. - */ - @JsonProperty("group") - public void setGroupId(Long groupId) { - this.group = new SymbolGroup(); - this.group.setId(groupId); - } - - /** - * Get the ID of the symbol. - * - * @return The ID. - */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @JsonProperty - public Long getId() { - return this.id; - } - - /** - * Set the ID of this symbol. - * - * @param id - * The new ID. - */ - @JsonProperty - public void setId(Long id) { - this.id = id; - } - - /** - * Get the name of the Symbol. - * - * @return The name. - */ - @NotBlank - @JsonProperty - public String getName() { - return name; - } - - /** - * Set the name of the Symbol. - * - * @param name - * The new name. - */ - @JsonProperty - public void setName(String name) { - this.name = name; - } - - @JsonProperty - @Column(columnDefinition = "TEXT") - public String getDescription() { - return description; - } - - @JsonProperty - public void setDescription(String description) { - this.description = description == null ? "" : description; - } - - @JsonProperty - @Column(columnDefinition = "TEXT") - public String getExpectedResult() { - return expectedResult; - } - - @Column - public void setExpectedResult(String expectedResult) { - this.expectedResult = expectedResult == null ? "" : expectedResult; - } - - /** - * Determine if the symbol is flagged as hidden. - * - * @return true if the symbol should be considered hidden; false otherwise. - */ - public boolean isHidden() { - return hidden; - } - - /** - * Mark the symbol as hidden or remove the hidden flag. - * - * @param hidden - * true if the symbol should be considered hidden; false otherwise. - */ - public void setHidden(boolean hidden) { - this.hidden = hidden; - } - - @JsonProperty - public String getSuccessOutput() { - return successOutput; - } - - @JsonProperty - public void setSuccessOutput(String successOutput) { - this.successOutput = successOutput; - } - - @OneToMany( - cascade = {CascadeType.REMOVE}, - orphanRemoval = true - ) - @OrderBy("name ASC") - @JsonProperty - public List getInputs() { - return inputs; - } - - @JsonProperty - public void setInputs(List inputs) { - this.inputs = inputs; - } - - @OneToMany( - cascade = {CascadeType.REMOVE}, - orphanRemoval = true - ) - @OrderBy("name ASC") - @JsonProperty - public List getOutputs() { - return outputs; - } - - @JsonProperty - public void setOutputs(List outputs) { - this.outputs = outputs; - } - - @OneToMany( - cascade = {CascadeType.REMOVE, CascadeType.MERGE}, - mappedBy = "symbol" - ) - @OrderBy("position ASC") - @JsonProperty - public List getSteps() { - return steps; - } - - @JsonProperty - public void setSteps(List steps) { - this.steps = steps; - } - - public ZonedDateTime getUpdatedOn() { - return updatedOn; - } - - public void setUpdatedOn(ZonedDateTime updatedOn) { - this.updatedOn = updatedOn; - } - - @Transient - @JsonProperty("updatedOn") - public String getUpdatedOnString() { - return updatedOn.format(Constants.DATE_TIME_FORMATTER); - } - - @JsonProperty("updatedOn") - public void setUpdatedOnString(String updatedOnString) { - this.updatedOn = updatedOnString == null ? ZonedDateTime.now() : ZonedDateTime.parse(updatedOnString); - } - - @Override - public ExecuteResult execute(ConnectorManager connectors) throws SULException { - logger.info(LoggerMarkers.LEARNER, "Executing Symbol {} ({})...", id, name); - - if (steps.isEmpty()) { - return new ExecuteResult(false, "Not implemented"); - } - - - final Map labels = getLabelsMap(); - - // assume the output is ok until proven otherwise - ExecuteResult result = new ExecuteResult(true); - - final long startTime = System.currentTimeMillis(); - for (int i = 0; i < steps.size(); i++) { - final SymbolStep step = steps.get(i); - - if (!step.isDisabled()) { - final ExecuteResult stepResult = step.execute(i, connectors); - - if (!stepResult.isSuccess() && !step.isIgnoreFailure()) { - if (step instanceof SymbolActionStep && ((SymbolActionStep) step).getAction() instanceof JumpToLabelAction) { - continue; - } - - result = stepResult; - - if (step.errorOutput != null && !step.errorOutput.equals("")) { - result.setMessage(SearchHelper.insertVariableValues(connectors, getProjectId(), step.errorOutput)); - } else { - result.setMessage(String.valueOf(i + 1)); - } - result.addTrace(this, result); - - break; - } else { - if (step instanceof SymbolActionStep && ((SymbolActionStep) step).getAction() instanceof JumpToLabelAction) { - final String label = ((JumpToLabelAction) ((SymbolActionStep) step).getAction()).getLabel(); - i = labels.get(label); - } - } - } - } - result.setTime(System.currentTimeMillis() - startTime); - - // set the output of the symbol *after* all actions are executed so that variables and counters have their - // proper values. - if (result.isSuccess()) { - if (successOutput != null && !successOutput.trim().equals("")) { - result.setMessage(SearchHelper.insertVariableValues(connectors, project.getId(), successOutput)); - } - } - - logger.info(LoggerMarkers.LEARNER, "Executed the Symbol {} ({}) => {}.", id, name, result); - - return result; - } - - /** - * Check if the given symbol contains a specific parameter in its inputs or outputs. - * - * @param parameter - * The parameter. - * @return If the parameter exists as input or output parameter. - */ - public boolean containsParameter(SymbolParameter parameter) { - final List parameters = new ArrayList<>(inputs); - parameters.addAll(outputs); - return parameters.contains(parameter); - } - - /** - * Adds a parameter. - * - * @param parameter - * The parameter to add. - */ - public void addParameter(SymbolParameter parameter) { - if (parameter instanceof SymbolInputParameter) { - this.inputs.add((SymbolInputParameter) parameter); - } else if (parameter instanceof SymbolOutputParameter) { - this.outputs.add((SymbolOutputParameter) parameter); - } - } - - /** - * Removes a parameter. - * - * @param parameter - * The parameter to remove. - */ - public void removeParameter(SymbolParameter parameter) { - if (parameter instanceof SymbolInputParameter) { - this.inputs.remove(parameter); - } else if (parameter instanceof SymbolOutputParameter) { - this.outputs.remove(parameter); - } - } - - @Transient - private Map getLabelsMap() { - final Map labelsMap = new HashMap<>(); - - for (int i = 0; i < steps.size(); i++) { - final SymbolStep step = steps.get(i); - if (step instanceof SymbolActionStep && ((SymbolActionStep) step).getAction() instanceof CreateLabelAction) { - final String label = ((CreateLabelAction) ((SymbolActionStep) step).getAction()).getLabel(); - labelsMap.put(label, i); - } - } - - return labelsMap; - } - - public SymbolInputParameter findInputByNameAndType(String name, SymbolParameter.ParameterType type) { - return this.inputs.stream() - .filter(i -> i.name.equals(name) && i.parameterType.equals(type)) - .findFirst() - .orElse(null); - } - - public SymbolOutputParameter findOutputByNameAndType(String name, SymbolParameter.ParameterType type) { - return this.outputs.stream() - .filter(i -> i.name.equals(name) && i.parameterType.equals(type)) - .findFirst() - .orElse(null); - } - - - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "lastUpdatedById") - @JsonProperty("lastUpdatedBy") - public User getLastUpdatedBy() { - return this.lastUpdatedBy; - } - - @JsonIgnore - public void setLastUpdatedBy(User user) { - this.lastUpdatedBy = user; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Symbol symbol = (Symbol) o; - if (getProjectId() == null || getId() == null) { - return Objects.equals(getName(), symbol.getName()); - } - return Objects.equals(getProjectId(), symbol.getProjectId()) - && Objects.equals(getGroupId(), symbol.getGroupId()) - && Objects.equals(getId(), symbol.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(getProjectId(), getGroupId(), getId()); - } - - @Override - public String toString() { - return "Symbol[" + id + "] " + this.project + "/" + this.getId() + ", " - + name + " #steps: " + steps.size(); - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/SymbolAction.java deleted file mode 100644 index d1ce8e56b..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolAction.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import de.learnlib.alex.common.utils.SearchHelper; -import de.learnlib.alex.data.entities.actions.misc.AssertCounterAction; -import de.learnlib.alex.data.entities.actions.misc.AssertVariableAction; -import de.learnlib.alex.data.entities.actions.misc.CreateLabelAction; -import de.learnlib.alex.data.entities.actions.misc.IncrementCounterAction; -import de.learnlib.alex.data.entities.actions.misc.JumpToLabelAction; -import de.learnlib.alex.data.entities.actions.misc.SetCounterAction; -import de.learnlib.alex.data.entities.actions.misc.SetVariableAction; -import de.learnlib.alex.data.entities.actions.misc.SetVariableByCookieAction; -import de.learnlib.alex.data.entities.actions.misc.SetVariableByHTMLElementAction; -import de.learnlib.alex.data.entities.actions.misc.SetVariableByHttpResponseAction; -import de.learnlib.alex.data.entities.actions.misc.SetVariableByHttpStatusAction; -import de.learnlib.alex.data.entities.actions.misc.SetVariableByJSONAttributeAction; -import de.learnlib.alex.data.entities.actions.misc.SetVariableByNodeAttributeAction; -import de.learnlib.alex.data.entities.actions.misc.SetVariableByNodeCountAction; -import de.learnlib.alex.data.entities.actions.misc.SetVariableByRegexGroupAction; -import de.learnlib.alex.data.entities.actions.misc.WaitAction; -import de.learnlib.alex.data.entities.actions.rest.CallAction; -import de.learnlib.alex.data.entities.actions.rest.CheckAttributeExistsAction; -import de.learnlib.alex.data.entities.actions.rest.CheckAttributeTypeAction; -import de.learnlib.alex.data.entities.actions.rest.CheckAttributeValueAction; -import de.learnlib.alex.data.entities.actions.rest.CheckHeaderFieldAction; -import de.learnlib.alex.data.entities.actions.rest.CheckStatusAction; -import de.learnlib.alex.data.entities.actions.rest.CheckTextRestAction; -import de.learnlib.alex.data.entities.actions.rest.RESTSymbolAction; -import de.learnlib.alex.data.entities.actions.rest.ValidateJsonAction; -import de.learnlib.alex.data.entities.actions.web.AlertAcceptDismissAction; -import de.learnlib.alex.data.entities.actions.web.AlertGetTextAction; -import de.learnlib.alex.data.entities.actions.web.AlertSendKeysAction; -import de.learnlib.alex.data.entities.actions.web.BrowserAction; -import de.learnlib.alex.data.entities.actions.web.CheckNodeAction; -import de.learnlib.alex.data.entities.actions.web.CheckNodeAttributeValueAction; -import de.learnlib.alex.data.entities.actions.web.CheckNodeSelectedAction; -import de.learnlib.alex.data.entities.actions.web.CheckPageTitleAction; -import de.learnlib.alex.data.entities.actions.web.CheckTextWebAction; -import de.learnlib.alex.data.entities.actions.web.ClearAction; -import de.learnlib.alex.data.entities.actions.web.ClickAction; -import de.learnlib.alex.data.entities.actions.web.ClickElementByTextAction; -import de.learnlib.alex.data.entities.actions.web.ClickLinkAction; -import de.learnlib.alex.data.entities.actions.web.DragAndDropAction; -import de.learnlib.alex.data.entities.actions.web.DragAndDropByAction; -import de.learnlib.alex.data.entities.actions.web.ExecuteScriptAction; -import de.learnlib.alex.data.entities.actions.web.FillAction; -import de.learnlib.alex.data.entities.actions.web.GotoAction; -import de.learnlib.alex.data.entities.actions.web.MoveMouseAction; -import de.learnlib.alex.data.entities.actions.web.PressKeyAction; -import de.learnlib.alex.data.entities.actions.web.SelectAction; -import de.learnlib.alex.data.entities.actions.web.SubmitAction; -import de.learnlib.alex.data.entities.actions.web.SwitchToAction; -import de.learnlib.alex.data.entities.actions.web.SwitchToFrameAction; -import de.learnlib.alex.data.entities.actions.web.UploadFileAction; -import de.learnlib.alex.data.entities.actions.web.WaitForNodeAction; -import de.learnlib.alex.data.entities.actions.web.WaitForNodeAttributeAction; -import de.learnlib.alex.data.entities.actions.web.WaitForScriptAction; -import de.learnlib.alex.data.entities.actions.web.WaitForTextAction; -import de.learnlib.alex.data.entities.actions.web.WaitForTitleAction; -import de.learnlib.alex.data.entities.actions.web.WebSymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import java.util.Objects; -import javax.persistence.DiscriminatorColumn; -import javax.persistence.DiscriminatorType; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Index; -import javax.persistence.Inheritance; -import javax.persistence.InheritanceType; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.Table; -import javax.persistence.Transient; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Abstract super type of how a Action for Symbols should look & work like. - */ -@Entity -@Table( - name = "ACTIONS", - indexes = @Index(columnList = "symbolId") -) -@Inheritance(strategy = InheritanceType.SINGLE_TABLE) -@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING) -@DiscriminatorValue("SUPER") -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") -@JsonSubTypes({ - @JsonSubTypes.Type(name = "wait", value = WaitAction.class), - // Counter & Variables - @JsonSubTypes.Type(name = "assertCounter", value = AssertCounterAction.class), - @JsonSubTypes.Type(name = "assertVariable", value = AssertVariableAction.class), - @JsonSubTypes.Type(name = "incrementCounter", value = IncrementCounterAction.class), - @JsonSubTypes.Type(name = "setCounter", value = SetCounterAction.class), - @JsonSubTypes.Type(name = "setVariable", value = SetVariableAction.class), - @JsonSubTypes.Type(name = "setVariableByJSON", value = SetVariableByJSONAttributeAction.class), - @JsonSubTypes.Type(name = "setVariableByHttpResponse", value = SetVariableByHttpResponseAction.class), - @JsonSubTypes.Type(name = "setVariableByHTML", value = SetVariableByHTMLElementAction.class), - @JsonSubTypes.Type(name = "setVariableByCookie", value = SetVariableByCookieAction.class), - @JsonSubTypes.Type(name = "setVariableByNodeAttribute", value = SetVariableByNodeAttributeAction.class), - @JsonSubTypes.Type(name = "setVariableByNodeCount", value = SetVariableByNodeCountAction.class), - @JsonSubTypes.Type(name = "setVariableByRegexGroup", value = SetVariableByRegexGroupAction.class), - @JsonSubTypes.Type(name = "setVariableByHttpStatus", value = SetVariableByHttpStatusAction.class), - @JsonSubTypes.Type(name = "createLabel", value = CreateLabelAction.class), - @JsonSubTypes.Type(name = "jumpToLabel", value = JumpToLabelAction.class), - // Web Actions - @JsonSubTypes.Type(name = "web", value = WebSymbolAction.class), - @JsonSubTypes.Type(name = "web_alertAcceptDismiss", value = AlertAcceptDismissAction.class), - @JsonSubTypes.Type(name = "web_alertGetText", value = AlertGetTextAction.class), - @JsonSubTypes.Type(name = "web_alertSendKeys", value = AlertSendKeysAction.class), - @JsonSubTypes.Type(name = "web_browser", value = BrowserAction.class), - @JsonSubTypes.Type(name = "web_checkNodeAttributeValue", value = CheckNodeAttributeValueAction.class), - @JsonSubTypes.Type(name = "web_checkForNode", value = CheckNodeAction.class), - @JsonSubTypes.Type(name = "web_checkForText", value = CheckTextWebAction.class), - @JsonSubTypes.Type(name = "web_checkNodeSelected", value = CheckNodeSelectedAction.class), - @JsonSubTypes.Type(name = "web_checkPageTitle", value = CheckPageTitleAction.class), - @JsonSubTypes.Type(name = "web_clear", value = ClearAction.class), - @JsonSubTypes.Type(name = "web_click", value = ClickAction.class), - @JsonSubTypes.Type(name = "web_clickElementByText", value = ClickElementByTextAction.class), - @JsonSubTypes.Type(name = "web_clickLinkByText", value = ClickLinkAction.class), - @JsonSubTypes.Type(name = "web_dragAndDrop", value = DragAndDropAction.class), - @JsonSubTypes.Type(name = "web_dragAndDropBy", value = DragAndDropByAction.class), - @JsonSubTypes.Type(name = "web_executeScript", value = ExecuteScriptAction.class), - @JsonSubTypes.Type(name = "web_fill", value = FillAction.class), - @JsonSubTypes.Type(name = "web_goto", value = GotoAction.class), - @JsonSubTypes.Type(name = "web_moveMouse", value = MoveMouseAction.class), - @JsonSubTypes.Type(name = "web_pressKey", value = PressKeyAction.class), - @JsonSubTypes.Type(name = "web_submit", value = SubmitAction.class), - @JsonSubTypes.Type(name = "web_select", value = SelectAction.class), - @JsonSubTypes.Type(name = "web_switchTo", value = SwitchToAction.class), - @JsonSubTypes.Type(name = "web_switchToFrame", value = SwitchToFrameAction.class), - @JsonSubTypes.Type(name = "web_uploadFile", value = UploadFileAction.class), - @JsonSubTypes.Type(name = "web_waitForTitle", value = WaitForTitleAction.class), - @JsonSubTypes.Type(name = "web_waitForNode", value = WaitForNodeAction.class), - @JsonSubTypes.Type(name = "web_waitForNodeAttribute", value = WaitForNodeAttributeAction.class), - @JsonSubTypes.Type(name = "web_waitForText", value = WaitForTextAction.class), - @JsonSubTypes.Type(name = "web_waitForScript", value = WaitForScriptAction.class), - // REST Actions - @JsonSubTypes.Type(name = "rest", value = RESTSymbolAction.class), - @JsonSubTypes.Type(name = "rest_call", value = CallAction.class), - @JsonSubTypes.Type(name = "rest_checkAttributeExists", value = CheckAttributeExistsAction.class), - @JsonSubTypes.Type(name = "rest_checkAttributeType", value = CheckAttributeTypeAction.class), - @JsonSubTypes.Type(name = "rest_checkAttributeValue", value = CheckAttributeValueAction.class), - @JsonSubTypes.Type(name = "rest_checkForText", value = CheckTextRestAction.class), - @JsonSubTypes.Type(name = "rest_checkHeaderField", value = CheckHeaderFieldAction.class), - @JsonSubTypes.Type(name = "rest_checkStatus", value = CheckStatusAction.class), - @JsonSubTypes.Type(name = "rest_validateJson", value = ValidateJsonAction.class), -}) -public abstract class SymbolAction { - - protected static final Logger logger = LoggerFactory.getLogger(SymbolAction.class); - - /** The ID of the Action in the DB. */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - protected Long id; - - /** The symbol the action belongs to. */ - @ManyToOne - @JoinColumn(name = "symbolId") - @JsonIgnore - protected Symbol symbol; - - /** The connections that the action can use. */ - @Transient - @JsonIgnore - private ConnectorManager connectorManager; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - /** - * Get the symbol the action is part of. - * - * @return The 'parent' symbol. - */ - public Symbol getSymbol() { - return symbol; - } - - /** - * Set a new symbol as 'parent' of the action. - * - * @param symbol - * The new related symbol. - */ - public void setSymbol(Symbol symbol) { - this.symbol = symbol; - } - - /** - * Execute the action. - * - * @param connectors - * The connectors that can be used. - * @return OK or FAILED. - */ - public ExecuteResult executeAction(ConnectorManager connectors) { - this.connectorManager = connectors; - return execute(connectors); - } - - /** - * Execute the Action. This is the important method in which all the magic will happen. - * - * @param connector - * The context to use. - * @return An {@link ExecuteResult} to indicate if the action run successfully or not. - */ - protected abstract ExecuteResult execute(ConnectorManager connector); - - /** - * Checks the given text for any occurrences of a variable and replaces this part with the actual value. The input - * string will not be modified. - * - * @param text - * The text to check for variables, which than will be replaced by the real value. - * @return The input string with all variables inserted. - */ - protected final String insertVariableValues(String text) { - return SearchHelper.insertVariableValues(connectorManager, symbol.getProjectId(), text); - } - - /** - * Get the proper return value for a successful action. This method checks the 'negated' field and should be used by - * all actions if no failure / error occurred. - * - * @return OK if 'negated' is false; FALSE if 'negated' is true. - */ - protected final ExecuteResult getSuccessOutput() { - return new ExecuteResult(true); - } - - /** - * Get the proper return value for a failed action. This method checks the 'negated' field and should be used by all - * actions if an failure / error occurred. - * - * @return FAILED if 'negated' is false; OK if 'negated' is true. - */ - protected final ExecuteResult getFailedOutput() { - return new ExecuteResult(false); - } - - //CHECKSTYLE.OFF: AvoidInlineConditionals|MagicNumber - auto generated by IntelliJ - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof SymbolAction)) { - return false; - } - - SymbolAction that = (SymbolAction) o; - - return Objects.equals(symbol, that.symbol); - } - - @Override - public int hashCode() { - return Objects.hash(getId(), getSymbol(), connectorManager); - } - //CHECKSTYLE.ON: AvoidInlineConditionals|MagicNumber - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolActionStep.java b/backend/src/main/java/de/learnlib/alex/data/entities/SymbolActionStep.java deleted file mode 100644 index 7064f3397..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolActionStep.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import java.io.Serializable; -import javax.persistence.CascadeType; -import javax.persistence.Entity; -import javax.persistence.OneToOne; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Executes an action on the SUL. - */ -@Entity -@JsonTypeName("action") -public class SymbolActionStep extends SymbolStep implements Serializable { - - private static final Logger logger = LoggerFactory.getLogger(SymbolActionStep.class); - - private static final long serialVersionUID = 5116902783136721652L; - - /** The action to execute. */ - @OneToOne(cascade = CascadeType.REMOVE) - private SymbolAction action; - - /** Constructor. */ - public SymbolActionStep() { - } - - /** - * Constructor. - * - * @param action - * The action to execute. - */ - public SymbolActionStep(SymbolAction action) { - this.action = action; - } - - @Override - public ExecuteResult execute(int i, ConnectorManager connectors) { - try { - return getExecuteResult(i, connectors, action.executeAction(connectors)); - } catch (Exception e) { - logger.error(LoggerMarkers.LEARNER, "The action could not be executed.", e); - return new ExecuteResult(false, String.valueOf(i + 1)); - } - } - - public SymbolAction getAction() { - return action; - } - - public void setAction(SymbolAction action) { - this.action = action; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolGroup.java b/backend/src/main/java/de/learnlib/alex/data/entities/SymbolGroup.java deleted file mode 100644 index c3e1a233a..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolGroup.java +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.function.Function; -import javax.persistence.CascadeType; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.OrderBy; -import javax.persistence.Transient; -import javax.validation.constraints.NotBlank; - -/** - * Entity to organize symbols. - */ -@Entity -@JsonInclude(JsonInclude.Include.NON_NULL) -public class SymbolGroup implements Serializable { - - private static final long serialVersionUID = 4986838799404559274L; - - /** The related project. */ - @ManyToOne(fetch = FetchType.EAGER, optional = false) - @JoinColumn(name = "projectId") - @JsonIgnore - private Project project; - - /** The ID of the group in the db. */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - /** The name of the group. */ - @NotBlank - private String name; - - /** The parent group. Is null if the group is on the top level. */ - @ManyToOne - @JoinColumn(name = "parentId") - @JsonIgnore - private SymbolGroup parent; - - /** The Symbols manged by this group. */ - @OneToMany( - mappedBy = "group", - cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE} - ) - private Set symbols; - - /** The child groups. */ - @OneToMany( - mappedBy = "parent", - cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE} - ) - @OrderBy("name ASC") - private List groups; - - /** Constructor. */ - public SymbolGroup() { - this.symbols = new HashSet<>(); - this.groups = new ArrayList<>(); - } - - public Project getProject() { - return project; - } - - public void setProject(Project project) { - this.project = project; - } - - /** - * Get the ID of the related project. - * - * @return The ID of the project the group belongs to or 0. - */ - @Transient - @JsonProperty("project") - public Long getProjectId() { - return project == null ? null : project.getId(); - } - - /** - * Create and set a new project by a new project ID. - * - * @param projectId - * The new project ID. - */ - @JsonProperty("project") - public void setProjectId(Long projectId) { - this.project = new Project(projectId); - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Set getSymbols() { - return symbols; - } - - public void setSymbols(Set symbols) { - this.symbols = symbols == null ? new HashSet<>() : symbols; - } - - public SymbolGroup getParent() { - return parent; - } - - public void setParent(SymbolGroup parent) { - this.parent = parent; - } - - /** - * Get the id of the parent group. - * - * @return The id of the parent group. - */ - @Transient - @JsonProperty("parent") - public Long getParentId() { - return this.parent == null ? null : this.parent.getId(); - } - - /** - * Set the parent by its id. - * - * @param parentId - * The id of the parent group or null. - */ - @JsonProperty("parent") - public void setParentId(Long parentId) { - if (parentId != null) { - this.parent = new SymbolGroup(); - this.parent.setId(parentId); - } - } - - public List getGroups() { - return groups; - } - - public void setGroups(List groups) { - this.groups = groups; - } - - /** - * Add one symbol to the group. - * - * @param symbol - * The symbol to add. - */ - @JsonIgnore - public void addSymbol(Symbol symbol) { - this.symbols.add(symbol); - symbol.setGroup(this); - } - - /** - * Check if the group is a descendant of another group. - * - * @param ancestor - * The ancestor in the group tree. - * @return True, if the group is a descendant. - */ - public boolean isDescendantOf(SymbolGroup ancestor) { - if (ancestor.equals(this)) { - return false; - } - - for (SymbolGroup group : ancestor.getGroups()) { - boolean isDescendant = group.equals(this) || isDescendantOf(group); - if (isDescendant) { - return true; - } - } - - return false; - } - - public void walk(Function groupFn, Function symbolFn) { - groupFn.apply(this); - symbols.forEach(symbolFn::apply); - groups.forEach(g -> g.walk(groupFn, symbolFn)); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - SymbolGroup group = (SymbolGroup) o; - return Objects.equals(id, group.id); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } - - @Override - public String toString() { - return "SymbolGroup[" + id + "]: " + project + ", " + name; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolInputParameter.java b/backend/src/main/java/de/learnlib/alex/data/entities/SymbolInputParameter.java deleted file mode 100644 index e7055a975..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolInputParameter.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonTypeName; -import java.util.ArrayList; -import java.util.List; -import javax.persistence.CascadeType; -import javax.persistence.Entity; -import javax.persistence.OneToMany; - -/** The input parameter. */ -@Entity -@JsonTypeName("input") -public class SymbolInputParameter extends SymbolParameter { - - private static final long serialVersionUID = 6221255069083369750L; - - /** The values for the parameter. */ - @OneToMany( - cascade = CascadeType.ALL, - mappedBy = "parameter" - ) - @JsonIgnore - private List parameterValues; - - /** Constructor. */ - public SymbolInputParameter() { - this.parameterValues = new ArrayList<>(); - } - - public List getParameterValues() { - return parameterValues; - } - - public void setParameterValues(List parameterValues) { - this.parameterValues = parameterValues; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolOutputMapping.java b/backend/src/main/java/de/learnlib/alex/data/entities/SymbolOutputMapping.java deleted file mode 100644 index 36284b4db..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolOutputMapping.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import java.io.Serializable; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.validation.constraints.NotEmpty; - -@Entity -public class SymbolOutputMapping implements Serializable { - - private static final long serialVersionUID = -1110680538349672576L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - /** The parameter for which its value is saved. */ - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "symbolParameterId") - private SymbolParameter parameter; - - /** The name for the parameter. */ - @NotEmpty - private String name; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public SymbolParameter getParameter() { - return parameter; - } - - public void setParameter(SymbolParameter parameter) { - this.parameter = parameter; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolOutputParameter.java b/backend/src/main/java/de/learnlib/alex/data/entities/SymbolOutputParameter.java deleted file mode 100644 index 558472ea4..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolOutputParameter.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import javax.persistence.Entity; - -/** The output parameter. */ -@Entity -@JsonTypeName("output") -public class SymbolOutputParameter extends SymbolParameter { - private static final long serialVersionUID = 9071112539204927316L; -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolPSymbolStep.java b/backend/src/main/java/de/learnlib/alex/data/entities/SymbolPSymbolStep.java deleted file mode 100644 index 6b2de0672..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolPSymbolStep.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import java.io.Serializable; -import javax.persistence.CascadeType; -import javax.persistence.Entity; -import javax.persistence.OneToOne; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Execute another symbol on the SUL. - */ -@Entity -@JsonTypeName("symbol") -public class SymbolPSymbolStep extends SymbolStep implements Serializable { - - private static final Logger logger = LoggerFactory.getLogger(SymbolPSymbolStep.class); - - /** The symbol to execute. */ - @OneToOne(cascade = CascadeType.REMOVE) - private ParameterizedSymbol pSymbol; - - @Override - public ExecuteResult execute(int i, ConnectorManager connectors) { - try { - return getExecuteResult(i, connectors, pSymbol.execute(connectors)); - } catch (Exception e) { - logger.error(LoggerMarkers.LEARNER, "The symbol could not be executed.", e); - return new ExecuteResult(false, String.valueOf(i + 1)); - } - } - - @JsonProperty("pSymbol") - public ParameterizedSymbol getPSymbol() { - return pSymbol; - } - - @JsonProperty("pSymbol") - public void setPSymbol(ParameterizedSymbol symbol) { - this.pSymbol = symbol; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolParameter.java b/backend/src/main/java/de/learnlib/alex/data/entities/SymbolParameter.java deleted file mode 100644 index a364e9d3f..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolParameter.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import java.io.Serializable; -import java.util.Objects; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.validation.constraints.NotBlank; - -/** - * Symbol parameter class. - */ -@Entity -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") -@JsonSubTypes({ - @JsonSubTypes.Type(name = "input", value = SymbolInputParameter.class), - @JsonSubTypes.Type(name = "output", value = SymbolOutputParameter.class), -}) -public abstract class SymbolParameter implements Serializable { - - private static final long serialVersionUID = -5863108479982983205L; - - /** The type of the parameter. */ - public enum ParameterType { - - /** If the parameter is a counter. */ - COUNTER, - - /** If the parameter is a string. */ - STRING - } - - /** The ID of the Action in the DB. */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - protected Long id; - - /** The symbol the action belongs to. */ - @ManyToOne - @JoinColumn(name = "symbolId") - @JsonIgnore - protected Symbol symbol; - - /** The name of the parameter. */ - @NotBlank - protected String name; - - /** The type of the parameter. */ - protected ParameterType parameterType; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Symbol getSymbol() { - return symbol; - } - - public void setSymbol(Symbol symbol) { - this.symbol = symbol; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public ParameterType getParameterType() { - return parameterType; - } - - public void setParameterType(ParameterType parameterType) { - this.parameterType = parameterType; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof SymbolParameter)) { - return false; - } - SymbolParameter parameter = (SymbolParameter) o; - return Objects.equals(getId(), parameter.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(getId()); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolParameterValue.java b/backend/src/main/java/de/learnlib/alex/data/entities/SymbolParameterValue.java deleted file mode 100644 index e6e9c9261..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolParameterValue.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import java.io.Serializable; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.Transient; -import javax.validation.constraints.NotEmpty; - -/** - * The value of a symbol parameter. - */ -@Entity -public class SymbolParameterValue implements Serializable { - - private static final long serialVersionUID = 2125637165072908329L; - - /** The id of the value in the db. */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - /** The parameter for which its value is saved. */ - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "symbolParameterId") - private SymbolParameter parameter; - - /** The value for the parameter. */ - @Column(name = "\"value\"") - @NotEmpty - private String value; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public SymbolParameter getParameter() { - return parameter; - } - - public void setParameter(SymbolParameter parameter) { - this.parameter = parameter; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - @JsonIgnore - @Transient - public void setDefaultValueByParameter(SymbolParameter parameter) { - if (parameter != null) { - if (parameter.getParameterType().equals(SymbolParameter.ParameterType.STRING)) { - value = "{{$" + parameter.getName() + "}}"; - } else { - value = "{{#" + parameter.getName() + "}}"; - } - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolStep.java b/backend/src/main/java/de/learnlib/alex/data/entities/SymbolStep.java deleted file mode 100644 index 57f9b694b..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolStep.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import de.learnlib.alex.common.utils.SearchHelper; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; - -/** - * A step that is executed when a symbol is executed. - */ -@Entity -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") -@JsonSubTypes({ - @JsonSubTypes.Type(name = "action", value = SymbolActionStep.class), - @JsonSubTypes.Type(name = "symbol", value = SymbolPSymbolStep.class), -}) -public abstract class SymbolStep { - - /** The ID of the step in the DB. */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - protected Long id; - - /** If the step is disabled and therefor should not be executed. */ - protected boolean disabled; - - /** If the failure should be ignored. */ - protected boolean ignoreFailure; - - /** If the result should be negated. */ - protected boolean negated; - - /** The custom output if the execution of this action fails. */ - protected String errorOutput; - - /** The position in the step list. */ - protected Integer position; - - /** The symbol that contains the step. */ - @ManyToOne(fetch = FetchType.EAGER, optional = false) - @JoinColumn(name = "symbolId") - @JsonIgnore - private Symbol symbol; - - /** Constructor. */ - public SymbolStep() { - this.disabled = false; - this.ignoreFailure = false; - this.negated = false; - } - - /** - * Execute the step. - * - * @param i - * The index of the step in the symbol. - * @param connectors - * The context to execute the step with. - * @return The result of the execution. - */ - public abstract ExecuteResult execute(int i, ConnectorManager connectors); - - /** - * Get the execute result. - * - * @param i - * The index of the step. - * @param connectors - * The connector manager. - * @param result - * The result from the step. - * @return The final result. - */ - protected ExecuteResult getExecuteResult(int i, ConnectorManager connectors, ExecuteResult result) { - if (!result.isSuccess() && errorOutput != null && !errorOutput.trim().equals("")) { - result.setMessage(errorOutput); - } - - if (negated) { - result.negate(); - } - - if (!result.isSuccess()) { - final String message = result.getMessage(); - if (message != null && !message.trim().equals("")) { - result.setMessage(SearchHelper.insertVariableValues(connectors, getSymbol().getProjectId(), message)); - } else { - result.setMessage(String.valueOf(i + 1)); - } - } - - return result; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public boolean isDisabled() { - return disabled; - } - - public void setDisabled(boolean disabled) { - this.disabled = disabled; - } - - public Symbol getSymbol() { - return symbol; - } - - public void setSymbol(Symbol symbol) { - this.symbol = symbol; - } - - @JsonProperty("symbol") - public Long getSymbolId() { - return symbol == null ? null : symbol.getId(); - } - - /** - * Set the referenced symbol by its ID. - * - * @param symbolId - * The ID of the symbol. - */ - @JsonProperty("symbol") - public void setSymbolId(Long symbolId) { - this.symbol = new Symbol(); - this.symbol.setId(symbolId); - } - - @JsonProperty("position") - public Integer getPosition() { - return position; - } - - @JsonProperty("position") - public void setPosition(Integer position) { - this.position = position; - } - - public boolean isIgnoreFailure() { - return ignoreFailure; - } - - public void setIgnoreFailure(boolean ignoreFailure) { - this.ignoreFailure = ignoreFailure; - } - - public boolean isNegated() { - return negated; - } - - public void setNegated(boolean negated) { - this.negated = negated; - } - - public String getErrorOutput() { - return errorOutput; - } - - public void setErrorOutput(String errorOutput) { - this.errorOutput = errorOutput; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolUsageResult.java b/backend/src/main/java/de/learnlib/alex/data/entities/SymbolUsageResult.java deleted file mode 100644 index f0e22a948..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/SymbolUsageResult.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import de.learnlib.alex.learning.entities.LearnerSetup; -import de.learnlib.alex.testing.entities.TestCase; -import java.util.HashSet; -import java.util.Set; - -public class SymbolUsageResult { - - private Set symbols; - private Set testCases; - private Set learnerSetups; - - public SymbolUsageResult() { - this.symbols = new HashSet<>(); - this.testCases = new HashSet<>(); - this.learnerSetups = new HashSet<>(); - } - - public Set getSymbols() { - return symbols; - } - - public void setSymbols(Set symbols) { - this.symbols = symbols; - } - - public Set getTestCases() { - return testCases; - } - - public void setTestCases(Set testCases) { - this.testCases = testCases; - } - - public Set getLearnerSetups() { - return learnerSetups; - } - - public void setLearnerSetups(Set learnerSetups) { - this.learnerSetups = learnerSetups; - } - - public boolean isInUse() { - return symbols.size() + testCases.size() + learnerSetups.size() > 0; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/UploadableFile.java b/backend/src/main/java/de/learnlib/alex/data/entities/UploadableFile.java deleted file mode 100644 index 2ecb3d78f..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/UploadableFile.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.OneToOne; -import javax.persistence.Table; -import javax.persistence.UniqueConstraint; -import javax.validation.constraints.NotBlank; - -/** - * Entity to describe a file which was uploaded. - */ -@Entity -@Table( - uniqueConstraints = @UniqueConstraint(columnNames = {"project_id", "name"}) -) -public class UploadableFile { - - /** The ID of the file reference. */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - /** The ID of the project the File belongs to. */ - @JsonIgnore - @OneToOne - private Project project; - - /** The name of the file. */ - @NotBlank - private String name; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Project getProject() { - return project; - } - - public void setProject(Project project) { - this.project = project; - } - - @JsonProperty("project") - public Long getProjectId() { - return project.getId(); - } - - @JsonProperty("project") - public void setProjectId(Long projectId) { - this.project = new Project(projectId); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/WebElementLocator.java b/backend/src/main/java/de/learnlib/alex/data/entities/WebElementLocator.java deleted file mode 100644 index e69046394..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/WebElementLocator.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import java.io.Serializable; -import java.util.Objects; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -/** - * Embeddable class that helps working with selenium web elements. - */ -@Embeddable -@JsonPropertyOrder(alphabetic = true) -public class WebElementLocator implements Serializable { - - private static final long serialVersionUID = -6070241271039096113L; - - /** - * The type of selectors. - */ - public enum Type { - - /** - * If the selector is a CSS selector. - */ - CSS, - - /** - * If the selector is an XPath expression. - */ - XPATH, - - /** - * If the element should be received by a JavaScript. - */ - JS - } - - /** - * The selector of the element[s]. - */ - @NotBlank - @Column(columnDefinition = "TEXT") - private String selector; - - /** - * What kind of selector {@link #selector} is. - */ - @NotNull - @Column(name = "selectorType") - private Type type; - - public WebElementLocator() { - } - - public WebElementLocator(String selector, Type type) { - this.selector = selector; - this.type = type; - } - - public String getSelector() { - return selector; - } - - public void setSelector(String selector) { - this.selector = selector; - } - - public Type getType() { - return type; - } - - public void setType(Type type) { - this.type = type; - } - - @Override - public String toString() { - return selector + "(" + type.toString() + ")"; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - WebElementLocator that = (WebElementLocator) o; - if (!Objects.equals(selector, that.selector)) { - return false; - } - return type == that.type; - } - - @Override - public int hashCode() { - int result = selector != null ? selector.hashCode() : 0; - result = 31 * result + (type != null ? type.hashCode() : 0); - return result; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/Credentials.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/Credentials.java deleted file mode 100644 index 8a4821361..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/Credentials.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions; - -import java.io.Serializable; -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import javax.persistence.Embeddable; - -/** - * Helper class to store and transfer authentication credentials, i.e. user name / email and password. - */ -@Embeddable -public class Credentials implements Serializable { - - private static final long serialVersionUID = 4146724090787542690L; - - /** The name to use for authentication. */ - private String name; - - /** The password to use for authentication. */ - private String password; - - /** - * Default constructor. - */ - public Credentials() { - this("", ""); - } - - /** - * Create a credential with a user and password. - * - * @param name - * The name to use. - * @param password - * The password to use. - */ - public Credentials(String name, String password) { - this.name = name; - this.password = password; - } - - /** - * Return the name and password encoded in Base64 to be used in for HTTP Basic Authentication. - * - * @return "name:password" encoded in Base64. - */ - public String toBase64() { - var credentialsAsString = name + ":" + password; - var credentialsAsByteArray = credentialsAsString.getBytes(StandardCharsets.UTF_8); - return Base64.getEncoder().encodeToString(credentialsAsByteArray); - } - - /** - * Check if the credentials are not empty. - * - * @return If the credentials are valid. - */ - public boolean areValid() { - return !name.trim().equals("") && !password.trim().equals(""); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/AssertCounterAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/AssertCounterAction.java deleted file mode 100644 index 8d7d23a02..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/AssertCounterAction.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.CounterStoreConnector; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -/** - * Action to assert the value of a counter. - */ -@Entity -@DiscriminatorValue("assertCounter") -@JsonTypeName("assertCounter") -public class AssertCounterAction extends SymbolAction { - - /** - * Assert types to mimic the different operators. - */ - public enum Operator { - - /** '<'. */ - LESS_THAN, - - /** '<='. */ - LESS_OR_EQUAL, - - /** '=='. */ - EQUAL, - - /** '>='. */ - GREATER_OR_EQUAL, - - /** '>'. */ - GREATER_THAN; - - /** - * Parser function to handle the enum names case insensitive. - * - * @param name - * The enum name. - * @return The corresponding CookieType. - * @throws IllegalArgumentException - * If the name could not be parsed. - */ - @JsonCreator - public static Operator fromString(String name) throws IllegalArgumentException { - return Operator.valueOf(name.toUpperCase()); - } - - @Override - public String toString() { - return name().toLowerCase(); - } - - } - - /** - * The name of the counter to assert. - */ - @NotBlank - private String name; - - /** - * The value to assert the counter content with. - */ - @NotNull - @Column(name = "assert_counter_value") - private Integer value; - - /** - * The method to compare the counter value with the one given. - */ - @NotNull - private Operator operator; - - @Override - protected ExecuteResult execute(ConnectorManager connector) { - CounterStoreConnector storeConnector = connector.getConnector(CounterStoreConnector.class); - Integer counterValue = storeConnector.get(name); - boolean result; - - switch (operator) { - case LESS_THAN: - result = counterValue < value; - break; - case LESS_OR_EQUAL: - result = counterValue <= value; - break; - case EQUAL: - result = counterValue.equals(value); - break; - case GREATER_OR_EQUAL: - result = counterValue >= value; - break; - case GREATER_THAN: - result = counterValue > value; - break; - default: - result = false; - break; - } - - logger.info(LoggerMarkers.LEARNER, "Asserting counter '{}' with value '{}' against '{}' using {} => {}.", - name, counterValue, value, operator, result); - - if (result) { - return getSuccessOutput(); - } else { - return getFailedOutput(); - } - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Integer getValue() { - return value; - } - - public void setValue(Integer value) { - this.value = value; - } - - public Operator getOperator() { - return operator; - } - - public void setOperator(Operator assertMethod) { - this.operator = assertMethod; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/AssertVariableAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/AssertVariableAction.java deleted file mode 100644 index 7aa160bdf..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/AssertVariableAction.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -/** - * Action to assert the equality of the content of a variable with a given string. - */ -@Entity -@DiscriminatorValue("assertVariable") -@JsonTypeName("assertVariable") -public class AssertVariableAction extends SymbolAction { - - /** - * The name of the variable to assert. - */ - @NotBlank - private String name; - - /** - * The value to assert the variable content with. - */ - @NotBlank - @Column(name = "\"value\"") - private String value; - - /** - * Whether the value of the variable is matched against a regular expression. - */ - @NotNull - @Column(name = "\"regexp\"") - private boolean regexp; - - /** Constructor. */ - public AssertVariableAction() { - this.regexp = false; - } - - @Override - protected ExecuteResult execute(ConnectorManager connector) { - final VariableStoreConnector variableStore = connector.getConnector(VariableStoreConnector.class); - final String variableValue = variableStore.get(name); - final String valueWithVariables = insertVariableValues(value); - - final boolean result; - if (regexp) { - result = variableValue.matches(valueWithVariables); - } else { - result = variableValue.equals(valueWithVariables); - } - - logger.info(LoggerMarkers.LEARNER, "Asserting variable '{}' with value '{}' against '{}' => {} (regex: {}).", - name, variableValue, valueWithVariables, result, regexp); - - if (result) { - return getSuccessOutput(); - } else { - return getFailedOutput(); - } - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - public boolean isRegexp() { - return regexp; - } - - public void setRegexp(boolean regexp) { - this.regexp = regexp; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/CreateLabelAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/CreateLabelAction.java deleted file mode 100644 index 5e568fd11..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/CreateLabelAction.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.NotBlank; - -@Entity -@DiscriminatorValue("createLabel") -@JsonTypeName("createLabel") -public class CreateLabelAction extends SymbolAction { - - @NotBlank - private String label; - - @Override - protected ExecuteResult execute(ConnectorManager connector) { - return new ExecuteResult(true); - } - - public String getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/IncrementCounterAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/IncrementCounterAction.java deleted file mode 100644 index d7e76837f..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/IncrementCounterAction.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.CounterStoreConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -/** - * Increment a counter by 1. - */ -@Entity -@DiscriminatorValue("incrementCounter") -@JsonTypeName("incrementCounter") -public class IncrementCounterAction extends SymbolAction { - - /** The name of the counter to increment. */ - @NotBlank - private String name; - - /** The value by which the counter should be incremented. */ - @NotNull - private int incrementBy; - - @Override - public ExecuteResult execute(ConnectorManager connector) { - CounterStoreConnector counterConnector = connector.getConnector(CounterStoreConnector.class); - counterConnector.incrementBy(symbol.getProjectId(), name, incrementBy); - - logger.info(LoggerMarkers.LEARNER, "Incremented counter '{}' by '{}'.", name, incrementBy); - return getSuccessOutput(); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getIncrementBy() { - return incrementBy; - } - - public void setIncrementBy(int incrementBy) { - this.incrementBy = incrementBy; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/JumpToLabelAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/JumpToLabelAction.java deleted file mode 100644 index 3eaad6cdb..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/JumpToLabelAction.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.data.utils.ExecuteScriptUtils; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.JavascriptExecutor; - -@Entity -@DiscriminatorValue("jumpToLabel") -@JsonTypeName("jumpToLabel") -public class JumpToLabelAction extends SymbolAction { - - @NotBlank - private String label; - - @NotBlank - @Column(columnDefinition = "TEXT") - private String script; - - @NotNull - private boolean async = false; - - @NotNull - @Min(value = 0) - private int timeout = 10; - - @Override - protected ExecuteResult execute(ConnectorManager connector) { - final WebSiteConnector webSiteConnector = connector.getConnector(WebSiteConnector.class); - - if (webSiteConnector.getDriver() instanceof JavascriptExecutor) { - - final Map> store = ExecuteScriptUtils.createScriptStore(connector); - - try { - webSiteConnector.getDriver().manage().timeouts().setScriptTimeout(timeout, TimeUnit.SECONDS); - - final Object returnValue; - if (async) { - returnValue = ((JavascriptExecutor) webSiteConnector.getDriver()).executeAsyncScript(script, store); - } else { - returnValue = ((JavascriptExecutor) webSiteConnector.getDriver()).executeScript(script, store); - } - - if (!(returnValue instanceof Boolean)) { - logger.info(LoggerMarkers.LEARNER, "Result of jump condition is not a boolean value."); - return getFailedOutput(); - } else { - final boolean canJump = (Boolean) returnValue; - if (canJump) { - logger.info(LoggerMarkers.LEARNER, "Jump to label '{}'.", label); - return getSuccessOutput(); - } else { - logger.info(LoggerMarkers.LEARNER, "Jump condition for label '" + label + "' not satisfied."); - return getFailedOutput(); - } - } - } catch (Exception e) { - logger.info(LoggerMarkers.LEARNER, "Could not execute JavaScript", e); - return getFailedOutput(); - } - } else { - logger.info(LoggerMarkers.LEARNER, "This driver does not support JavaScript!"); - return getFailedOutput(); - } - } - - public String getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } - - public String getScript() { - return script; - } - - public void setScript(String script) { - this.script = script; - } - - public boolean isAsync() { - return async; - } - - public void setAsync(boolean async) { - this.async = async; - } - - public int getTimeout() { - return timeout; - } - - public void setTimeout(int timeout) { - this.timeout = timeout; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetCounterAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetCounterAction.java deleted file mode 100644 index 0089ccffe..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetCounterAction.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.CounterStoreConnector; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -/** - * Action to set a counter to a specific value. - */ -@Entity -@DiscriminatorValue("setCounter") -@JsonTypeName("setCounter") -public class SetCounterAction extends SymbolAction { - - /** - * How {@link SetCounterAction#value} should be interpreted. - */ - public enum ValueType { - - /** - * As number. - */ - NUMBER, - - /** - * As value from a current variable. - */ - VARIABLE - } - - /** - * The name of the counter to set a new value to. - */ - @NotBlank - private String name; - - /** - * The new value. - */ - @NotNull - @Column(name = "\"value\"") - private String value; - - /** - * How {@link SetCounterAction#value} should be interpreted. - */ - @NotNull - private ValueType valueType; - - @Override - public ExecuteResult execute(ConnectorManager connector) { - CounterStoreConnector counterStoreConnector = connector.getConnector(CounterStoreConnector.class); - VariableStoreConnector variableStoreConnector = connector.getConnector(VariableStoreConnector.class); - - int val; - try { - switch (valueType) { - case VARIABLE: - val = Integer.parseInt(variableStoreConnector.get(value)); - break; - case NUMBER: - val = Integer.parseInt(value); - break; - default: - val = 0; - break; - } - } catch (NumberFormatException | IllegalStateException e) { - logger.info(LoggerMarkers.LEARNER, "Could not set the counter '{}' to the value '{}' ", name, value, e); - - return getFailedOutput(); - } - - counterStoreConnector.set(symbol.getProjectId(), name, val); - - logger.info(LoggerMarkers.LEARNER, "Set the counter '{}' to the value '{}'.", name, value); - return getSuccessOutput(); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - public ValueType getValueType() { - return valueType; - } - - public void setValueType(ValueType valueType) { - this.valueType = valueType; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableAction.java deleted file mode 100644 index 4f91aee69..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableAction.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -/** - * Set a variable to a specific value. - */ -@Entity -@DiscriminatorValue("setVariable") -@JsonTypeName("setVariable") -public class SetVariableAction extends SymbolAction { - - /** The name of the variable to set a new value to. */ - @NotBlank - protected String name; - - /** The new value. */ - @NotNull - @Column(name = "\"value\"") - protected String value; - - @Override - public ExecuteResult execute(ConnectorManager connector) { - VariableStoreConnector storeConnector = connector.getConnector(VariableStoreConnector.class); - storeConnector.set(name, insertVariableValues(value)); - - logger.info(LoggerMarkers.LEARNER, "Set the variable '{}' to the value '{}'.", name, value); - return getSuccessOutput(); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByCookieAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByCookieAction.java deleted file mode 100644 index 931c8595e..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByCookieAction.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebServiceConnector; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import java.util.Map; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.NotNull; -import javax.ws.rs.core.NewCookie; -import org.openqa.selenium.Cookie; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebDriver; - -/** - * Action to set the value of a variable based on a response cookie. - */ -@Entity -@DiscriminatorValue("setVariableByCookie") -@JsonTypeName("setVariableByCookie") -public class SetVariableByCookieAction extends SetVariableAction { - - /** - * The type of the cookie. Either by selenium cookie or from a http request. - */ - @NotNull - private CookieType cookieType; - - @Override - public ExecuteResult execute(ConnectorManager connector) { - VariableStoreConnector storeConnector = connector.getConnector(VariableStoreConnector.class); - WebServiceConnector webServiceConnector = connector.getConnector(WebServiceConnector.class); - WebSiteConnector webSiteConnector = connector.getConnector(WebSiteConnector.class); - - try { - String cookieValue = null; - - if (cookieType == CookieType.WEB) { - WebDriver driver = webSiteConnector.getDriver(); - WebDriver.Options manage = driver.manage(); - Cookie cookie = manage.getCookieNamed(value); - if (cookie != null) { - cookieValue = cookie.getValue(); - } - } else if (cookieType == CookieType.REST) { - Map cookies = webServiceConnector.getCookies(); - javax.ws.rs.core.Cookie cookie = cookies.get(value); - if (cookie != null) { - cookieValue = cookie.getValue(); - } - } else { - logger.warn(LoggerMarkers.LEARNER, "Could not set the variable '{}' to the cookie '{}' because the " - + "type '{}' is not supported!", name, value, cookieType); - return getFailedOutput(); - } - - if (cookieValue != null) { - storeConnector.set(name, cookieValue); - logger.info(LoggerMarkers.LEARNER, "Set the variable '{}' to the value '{}' of the cookie '{}:{}' ", - name, cookieValue, cookieType, value); - return getSuccessOutput(); - } else { - logger.info(LoggerMarkers.LEARNER, "Could not set the variable '{}' to the cookie '{}:{}' because " - + "the cookie was not found!", name, cookieType, value); - return getFailedOutput(); - } - } catch (IllegalStateException | NoSuchElementException e) { - logger.warn(LoggerMarkers.LEARNER, "Could not set the variable '{}' to the cookie '{}' because of an " - + "error.", name, value, e); - return getFailedOutput(); - } - } - - public CookieType getCookieType() { - return cookieType; - } - - public void setCookieType(CookieType type) { - cookieType = type; - } - - /** - * Enum to differentiate web & REST cookies. - */ - public enum CookieType { - - /** Cookies from or to a web interface. */ - WEB, - - /** Cookies from or to an REST interface. */ - REST; - - /** - * Parser function to handle the enum names case insensitive. - * - * @param name - * The enum name. - * @return The corresponding CookieType. - * @throws IllegalArgumentException - * If the name could not be parsed. - */ - @JsonCreator - public static CookieType fromString(String name) throws IllegalArgumentException { - return CookieType.valueOf(name.toUpperCase()); - } - - @Override - public String toString() { - return name().toLowerCase(); - } - - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByHTMLElementAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByHTMLElementAction.java deleted file mode 100644 index 4a41ed1a3..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByHTMLElementAction.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.NoSuchElementException; - -/** - * Action to set a variable to a value received from an element of the DOM tree. - */ -@Entity -@DiscriminatorValue("setVariableByHTML") -@JsonTypeName("setVariableByHTML") -public class SetVariableByHTMLElementAction extends SymbolAction { - - /** The name of the variable. */ - @NotBlank - protected String name; - - /** The locator of the element. */ - @NotNull - @Embedded - private WebElementLocator node; - - @Override - public ExecuteResult execute(ConnectorManager connector) { - VariableStoreConnector storeConnector = connector.getConnector(VariableStoreConnector.class); - WebSiteConnector webSiteConnector = connector.getConnector(WebSiteConnector.class); - - final WebElementLocator nodeWithVariables = - new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - - try { - String text = webSiteConnector.getElement(nodeWithVariables).getText().trim(); - storeConnector.set(name, text); - - logger.info(LoggerMarkers.LEARNER, "Set the variable '{}' to the value '{}' of the HTML node '{}':", - name, text, nodeWithVariables); - return getSuccessOutput(); - } catch (NoSuchElementException e) { - logger.info(LoggerMarkers.LEARNER, "Could not set the variable '{}' to the value of the HTML node '{}'.", - name, nodeWithVariables); - return getFailedOutput(); - } - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public WebElementLocator getNode() { - return node; - } - - public void setNode(WebElementLocator node) { - this.node = node; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByHttpResponseAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByHttpResponseAction.java deleted file mode 100644 index 934b8a490..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByHttpResponseAction.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebServiceConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.NotEmpty; - -/** - * Action to set a variable to the body of the last HTTP response. - */ -@Entity -@DiscriminatorValue("setVariableByHttpResponse") -@JsonTypeName("setVariableByHttpResponse") -public class SetVariableByHttpResponseAction extends SymbolAction { - - /** - * The name of the variable. - */ - @NotEmpty - private String name; - - @Override - public ExecuteResult execute(ConnectorManager connector) { - final WebServiceConnector webServiceConnector = connector.getConnector(WebServiceConnector.class); - final VariableStoreConnector variableStore = connector.getConnector(VariableStoreConnector.class); - - try { - final String body = webServiceConnector.getBody(); - variableStore.set(name, body); - - logger.info(LoggerMarkers.LEARNER, "Set variable '{}' to HTTP body.", name); - return getSuccessOutput(); - } catch (Exception e) { - logger.info(LoggerMarkers.LEARNER, "Could not set variable '{}' to HTTP body.", name); - return getFailedOutput(); - } - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByHttpStatusAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByHttpStatusAction.java deleted file mode 100644 index 2c152c18a..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByHttpStatusAction.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebServiceConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.NotEmpty; - -/** Sets a variable by the status of an HTTP response. */ -@Entity -@DiscriminatorValue("setVariableByHttpStatus") -@JsonTypeName("setVariableByHttpStatus") -public class SetVariableByHttpStatusAction extends SymbolAction { - - /** The name of the variable. */ - @NotEmpty - private String name; - - @Override - public ExecuteResult execute(ConnectorManager connector) { - final WebServiceConnector webServiceConnector = connector.getConnector(WebServiceConnector.class); - final VariableStoreConnector variableStore = connector.getConnector(VariableStoreConnector.class); - - try { - final int status = webServiceConnector.getStatus(); - variableStore.set(name, String.valueOf(status)); - - logger.info(LoggerMarkers.LEARNER, "Set variable '{}' to status '{}'.", name, status); - return getSuccessOutput(); - } catch (Exception e) { - logger.info(LoggerMarkers.LEARNER, "Could not set variable '{}'", name); - return getFailedOutput(); - } - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByJSONAttributeAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByJSONAttributeAction.java deleted file mode 100644 index 9c8350128..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByJSONAttributeAction.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.JSONHelpers; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebServiceConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; - -/** - * Action to set a variable to a value received from an element of the current (JSON) body. - */ -@Entity -@DiscriminatorValue("setVariableByJSON") -@JsonTypeName("setVariableByJSON") -public class SetVariableByJSONAttributeAction extends SetVariableAction { - - @Override - public ExecuteResult execute(ConnectorManager connector) { - VariableStoreConnector storeConnector = connector.getConnector(VariableStoreConnector.class); - WebServiceConnector webServiceConnector = connector.getConnector(WebServiceConnector.class); - - String body = webServiceConnector.getBody(); - String valueInTheBody = JSONHelpers.getAttributeValue(body, value); - - if (valueInTheBody == null) { - logger.info(LoggerMarkers.LEARNER, "Could not set variable '{}' to the value of the JSON attribute '{}' ", - name, value); - return getFailedOutput(); - } - - storeConnector.set(name, valueInTheBody); - return getSuccessOutput(); - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByNodeAttributeAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByNodeAttributeAction.java deleted file mode 100644 index 933d099eb..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByNodeAttributeAction.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.NoSuchElementException; - -/** - * Action to set a variable to the value of an attribute of an HTML node. - */ -@Entity -@DiscriminatorValue("setVariableByNodeAttribute") -@JsonTypeName("setVariableByNodeAttribute") -public class SetVariableByNodeAttributeAction extends SymbolAction { - - /** The name of the variable. */ - @NotBlank - protected String name; - - /** The node to look for. */ - @NotNull - @Embedded - protected WebElementLocator node; - - /** The attribute name of the node to look for. */ - @NotBlank - protected String attribute; - - @Override - protected ExecuteResult execute(ConnectorManager connector) { - VariableStoreConnector storeConnector = connector.getConnector(VariableStoreConnector.class); - WebSiteConnector webSiteConnector = connector.getConnector(WebSiteConnector.class); - - final WebElementLocator nodeWithVariables = - new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - - try { - String value = webSiteConnector.getElement(nodeWithVariables).getAttribute(attribute); - storeConnector.set(name, value); - - logger.info(LoggerMarkers.LEARNER, "Set variable '{}' to attribute '{}' of element '{}'.", - name, attribute, nodeWithVariables); - - return getSuccessOutput(); - } catch (NoSuchElementException e) { - logger.info(LoggerMarkers.LEARNER, "Could not set variable '{}' to attribute '{}' of element '{}'.", - name, attribute, nodeWithVariables); - - return getFailedOutput(); - } - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public WebElementLocator getNode() { - return node; - } - - public void setNode(WebElementLocator node) { - this.node = node; - } - - public String getAttribute() { - return attribute; - } - - public void setAttribute(String attribute) { - this.attribute = attribute; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByNodeCountAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByNodeCountAction.java deleted file mode 100644 index b47e33fd4..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByNodeCountAction.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.NoSuchElementException; - -/** - * Counts elements that match a given selector and stores the result into a variable. - */ -@Entity -@DiscriminatorValue("setVariableByNodeCount") -@JsonTypeName("setVariableByNodeCount") -public class SetVariableByNodeCountAction extends SymbolAction { - - /** The name of the variable. */ - @NotBlank - private String name; - - /** The selector of the elements. */ - @NotNull - @Embedded - private WebElementLocator node; - - @Override - protected ExecuteResult execute(ConnectorManager connector) { - int nodeCount = 0; - final WebElementLocator nodeWithVariables = - new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - - try { - nodeCount = connector.getConnector(WebSiteConnector.class) - .getElements(nodeWithVariables) - .size(); - } catch (NoSuchElementException e) { - logger.info(LoggerMarkers.LEARNER, "Could not find elements with the selector '{}'.", - nodeWithVariables); - } - - connector.getConnector(VariableStoreConnector.class) - .set(name, String.valueOf(nodeCount)); - - return getSuccessOutput(); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public WebElementLocator getNode() { - return node; - } - - public void setNode(WebElementLocator node) { - this.node = node; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByRegexGroupAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByRegexGroupAction.java deleted file mode 100644 index e9a668b85..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByRegexGroupAction.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -/** - * Action that, given a regular expression, searches in the page source for matches. If a match is found, it extracts - * the nth group, e.g. (.*?) in the regex, and saves the value into a variable. - */ -@Entity -@DiscriminatorValue("setVariableByRegexGroup") -@JsonTypeName("setVariableByRegexGroup") -public class SetVariableByRegexGroupAction extends SymbolAction { - - /** The name of the variable. */ - @NotBlank - private String name; - - /** The regex to search in the page source. */ - @NotBlank - private String regex; - - /** Which match should be used. */ - @NotNull - @Min(1) - private int nthMatch; - - /** Which group in the match should be used. */ - @NotNull - @Min(0) - private int mthGroup; - - @Override - protected ExecuteResult execute(ConnectorManager connector) { - String pageSource = connector.getConnector(WebSiteConnector.class) - .getDriver() - .getPageSource(); - - Matcher matcher = Pattern.compile(regex) - .matcher(pageSource); - - try { - boolean matchFound = false; - int i = 1; - - while (matcher.find()) { - if (i == nthMatch) { - String group = matcher.group(mthGroup); - connector.getConnector(VariableStoreConnector.class) - .set(name, group); - matchFound = true; - break; - } - i++; - } - - if (!matchFound) { - logger.info(LoggerMarkers.LEARNER, "Could not find a string that matches regex '{}' ", regex); - return getFailedOutput(); - } - } catch (IndexOutOfBoundsException e) { - logger.info(LoggerMarkers.LEARNER, "Could not find group {} in regex '{}' ", mthGroup, regex); - return getFailedOutput(); - } - - return getSuccessOutput(); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getRegex() { - return regex; - } - - public void setRegex(String regex) { - this.regex = regex; - } - - public int getNthMatch() { - return nthMatch; - } - - public void setNthMatch(int nthMatch) { - this.nthMatch = nthMatch; - } - - public int getMthGroup() { - return mthGroup; - } - - public void setMthGroup(int mthGroup) { - this.mthGroup = mthGroup; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/WaitAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/WaitAction.java deleted file mode 100644 index 8daefe914..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/misc/WaitAction.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; - -/** - * Action to wait for a specific amount of time. - */ -@Entity -@DiscriminatorValue("wait") -@JsonTypeName("wait") -public class WaitAction extends SymbolAction { - - /** - * The duration to wait in ms. - */ - @NotNull - @Min(0) - private Long duration; - - @Override - public ExecuteResult execute(ConnectorManager connector) { - try { - logger.info(LoggerMarkers.LEARNER, "Waiting for {} ms.", duration); - Thread.sleep(duration); - return getSuccessOutput(); - } catch (InterruptedException e) { - logger.error(LoggerMarkers.LEARNER, "Failed to wait.", e); - return getFailedOutput(); - } - } - - public Long getDuration() { - return duration; - } - - public void setDuration(Long duration) { - this.duration = duration; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CallAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CallAction.java deleted file mode 100644 index 0ef700767..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CallAction.java +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.rest; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.actions.Credentials; -import de.learnlib.alex.learning.services.connectors.WebServiceConnector; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.persistence.Lob; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.ws.rs.core.Cookie; -import org.hibernate.annotations.Type; -import org.springframework.util.SerializationUtils; - -/** - * RESTSymbolAction to make a request to the API. - */ -@Entity -@DiscriminatorValue("rest_call") -@JsonTypeName("rest_call") -public class CallAction extends RESTSymbolAction { - - /** - * Enumeration to specify the HTTP method. - */ - public enum Method { - GET, - POST, - PUT, - DELETE, - PATCH - } - - /** - * The method to use for the call. - */ - @NotNull - private Method method; - - /** - * The url to call. - * The URL can either be a path relative to the project's base URL or a absolute URL that starts with https?:// - */ - @NotBlank - private String url; - - @NotBlank - private String baseUrl; - - /** The amount of time in ms before the request is aborted. The value 0 means wait infinitely long. */ - @NotNull - @Min(value = 0) - private int timeout; - - /** - * Map to store headers, that will be send with the requests. Every header name has a list of values, to be standard - * conform (e.g. Accept: text/html,application/xml). - */ - @Lob - @Column(columnDefinition = "BYTEA") - @Type(type = "org.hibernate.type.BinaryType") - private byte[] headers; - - /** - * Optional credentials to authenticate via HTTP basic auth. - */ - @Embedded - private Credentials credentials; - - /** - * Map to store cookies, that will be send with the request. Cookies are a normal header field, but this should make - * things easier. - */ - @Lob - @Column(columnDefinition = "BYTEA") - @Type(type = "org.hibernate.type.BinaryType") - private byte[] cookies; // OM NOM NOM NOM!!! - - /** - * Optional data to sent with a POST or PUT request. - */ - @Column(columnDefinition = "TEXT") - private String data; - - /** - * Default constructor that just initializes the internal data structures. - */ - public CallAction() { - this.timeout = 0; - } - - @Override - public ExecuteResult execute(WebServiceConnector target) { - try { - logger.info(LoggerMarkers.LEARNER, "Doing {} request to '{}'.", method, url); - doRequest(target); - return getSuccessOutput(); - } catch (Exception e) { - logger.info(LoggerMarkers.LEARNER, "Could not call {}.", getUrlWithVariableValues(), e); - return getFailedOutput(); - } - } - - public Method getMethod() { - return method; - } - - public void setMethod(Method method) { - this.method = method; - } - - public String getUrl() { - return url; - } - - /** - * Get the URL the request will go to. In the URL all the variables and counters will be replace with their values. - * - * @return The URL which will be called. - */ - private String getUrlWithVariableValues() { - return insertVariableValues(url); - } - - public void setUrl(String url) { - this.url = url; - } - - public HashMap getHeaders() { - if (headers == null) { - return new HashMap<>(); - } - return (HashMap) SerializationUtils.deserialize(headers); - } - - /** - * Like {@link #getHeaders()}, but all values of the header fields will have variables and counters inserted. - * - * @return The map of request headers, with the actual values of counters and variables in their values. - */ - private Map getHeadersWithVariableValues() { - Map result = new HashMap<>(); - getHeaders().forEach((k, v) -> result.put(k, insertVariableValues(v))); - return result; - } - - public void setHeaders(HashMap headers) { - this.headers = SerializationUtils.serialize(headers); - } - - public Credentials getCredentials() { - return credentials; - } - - /** - * Like {@link #getCredentials()}, but the name and password will have all variables and counters inserted. - * - * @return The credentials to use, with the actual values of counters and variables in their values. - */ - private Credentials getCredentialsWithVariableValues() { - if (credentials == null) { - return new Credentials(); - } - - String name = insertVariableValues(credentials.getName()); - String password = insertVariableValues(credentials.getPassword()); - - return new Credentials(name, password); - } - - public void setCredentials(Credentials credentials) { - this.credentials = credentials; - } - - public HashMap getCookies() { - if (cookies == null) { - return new HashMap<>(); - } - return (HashMap) SerializationUtils.deserialize(cookies); - } - - /** - * Creates a new Set of Cookies out of the map of cookies. In every cookie value the counter and variables are - * replaced with their actual value. - * - * @return A new Set of Cookies, with the actual variable and counter values. - */ - private Set getCookiesWithVariableValues() { - Set result = new HashSet<>(); - getCookies().forEach((n, v) -> result.add(new Cookie(n, insertVariableValues(v)))); - return result; - } - - public void setCookies(HashMap cookies) { - this.cookies = SerializationUtils.serialize(cookies); - } - - public String getData() { - return data; - } - - /** - * Get the optional data which will be send together with a POST or PUT request. All variables and counters will be - * replaced with their values. - * - * @return The data to include in the next POST/ PUT request. - */ - private String getDataWithVariableValues() { - return insertVariableValues(data); - } - - public void setData(String data) { - this.data = data; - } - - public int getTimeout() { - return timeout; - } - - public void setTimeout(int timeout) { - this.timeout = timeout; - } - - public String getBaseUrl() { - return baseUrl; - } - - public void setBaseUrl(String baseUrl) { - this.baseUrl = baseUrl; - } - - private void doRequest(WebServiceConnector target) throws Exception { - final Map requestHeaders = getHeadersWithVariableValues(); - if (credentials != null && credentials.areValid()) { - logger.info(LoggerMarkers.LEARNER, "Using credentials '{}'.", credentials); - requestHeaders.put("Authorization", "Basic " + getCredentialsWithVariableValues().toBase64()); - } - - switch (method) { - case GET: - target.get(baseUrl, getUrlWithVariableValues(), requestHeaders, getCookiesWithVariableValues(), timeout); - break; - case POST: - target.post(baseUrl, getUrlWithVariableValues(), requestHeaders, getCookiesWithVariableValues(), - getDataWithVariableValues(), timeout); - break; - case PUT: - target.put(baseUrl, getUrlWithVariableValues(), requestHeaders, getCookiesWithVariableValues(), - getDataWithVariableValues(), timeout); - break; - case DELETE: - target.delete(baseUrl, getUrlWithVariableValues(), requestHeaders, getCookiesWithVariableValues(), timeout); - break; - case PATCH: - target.patch(baseUrl, getUrlWithVariableValues(), requestHeaders, getCookiesWithVariableValues(), - getDataWithVariableValues(), timeout); - break; - default: - logger.error(LoggerMarkers.LEARNER, "Tried to make a call to a REST API with an unknown method '{}'.", - method.name()); - } - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CheckAttributeExistsAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CheckAttributeExistsAction.java deleted file mode 100644 index c018c5796..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CheckAttributeExistsAction.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.rest; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.JSONHelpers; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.learning.services.connectors.WebServiceConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.Transient; -import javax.validation.constraints.NotBlank; - -/** - * RESTSymbolAction to check if the request body of the last request has a JSON attribute with a specific name. - */ -@Entity -@DiscriminatorValue("rest_checkAttributeExists") -@JsonTypeName("rest_checkAttributeExists") -public class CheckAttributeExistsAction extends RESTSymbolAction { - - /** The name of the attribute to check for. */ - @NotBlank - private String attribute; - - @Override - public ExecuteResult execute(WebServiceConnector target) { - String body = target.getBody(); - - boolean result = JSONHelpers.getAttributeValue(body, getAttributeWithVariableValues()) != null; - - logger.info(LoggerMarkers.LEARNER, "Check if the attribute '{}' exists in '{}' => {}.", - attribute, body, result); - if (result) { - return getSuccessOutput(); - } else { - return getFailedOutput(); - } - } - - public String getAttribute() { - return attribute; - } - - /** - * Get the field name of the requested attribute. All variables and counters will be replaced with their values. - * - * @return The name of the attribute. - */ - @Transient - @JsonIgnore - public String getAttributeWithVariableValues() { - return insertVariableValues(attribute); - } - - public void setAttribute(String attribute) { - this.attribute = attribute; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CheckAttributeTypeAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CheckAttributeTypeAction.java deleted file mode 100644 index ade2a7856..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CheckAttributeTypeAction.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.rest; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonTypeName; -import com.fasterxml.jackson.databind.node.JsonNodeType; -import de.learnlib.alex.common.utils.JSONHelpers; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.learning.services.connectors.WebServiceConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.Transient; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -/** - * RESTSymbolAction to check if the request body of the last request has a JSON attribute with a specific type. - */ -@Entity -@DiscriminatorValue("rest_checkAttributeType") -@JsonTypeName("rest_checkAttributeType") -public class CheckAttributeTypeAction extends RESTSymbolAction { - - /** - * Enumeration to refer to a type of a JSON field. - */ - public enum JsonType { - - /** NULL POINTER INCOMMMMING!!!1111. */ - NULL(JsonNodeType.NULL), - - /** The attribute has a string value. */ - STRING(JsonNodeType.STRING), - - /** The attribute has a integer value. */ - INTEGER(JsonNodeType.NUMBER), - - /** The attribute has a boolean value. */ - BOOLEAN(JsonNodeType.BOOLEAN), - - /** The attribute has an object as value. */ - OBJECT(JsonNodeType.OBJECT), - - /** The attribute has an array as value. */ - ARRAY(JsonNodeType.ARRAY), - - /** The attribute has unknown or missing type. */ - UNKNOWN(JsonNodeType.MISSING); - - /** Connection between our minimal type set and the bigger one from Jackson. */ - private final JsonNodeType relatedType; - - /** - * Internal constructor to set the related types. - * - * @param relatedType - * The type use by Jackson which is equal to our system. - */ - JsonType(JsonNodeType relatedType) { - this.relatedType = relatedType; - } - - /** - * Get the JSON type used by Jackson which is equal to the type. - * - * @return The equal JSON type used by Jackson. - */ - public JsonNodeType getRelatedType() { - return relatedType; - } - } - - /** The name of the attribute to check for. */ - @NotBlank - private String attribute; - - /** The JSON type the attribute should have. */ - @NotNull - private JsonType jsonType; - - @Override - public ExecuteResult execute(WebServiceConnector target) { - String body = target.getBody(); - JsonType typeInBody = JSONHelpers.getAttributeType(body, getAttributeWithVariableValues()); - - boolean result = typeInBody != null && typeInBody.equals(jsonType); - - logger.info(LoggerMarkers.LEARNER, "Check if the attribute '{}' has the type '{}' in '{}' => {}.", - attribute, jsonType, body, result); - if (result) { - return getSuccessOutput(); - } else { - return getFailedOutput(); - } - } - - public String getAttribute() { - return attribute; - } - - /** - * Get the field name of the requested attribute. All variables and counters will be replaced with their values. - * - * @return The name of the attribute. - */ - @Transient - @JsonIgnore - public String getAttributeWithVariableValues() { - return insertVariableValues(attribute); - } - - public void setAttribute(String attribute) { - this.attribute = attribute; - } - - public JsonType getJsonType() { - return jsonType; - } - - public void setJsonType(JsonType jsonType) { - this.jsonType = jsonType; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CheckAttributeValueAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CheckAttributeValueAction.java deleted file mode 100644 index 66a5e64ca..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CheckAttributeValueAction.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.rest; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.JSONHelpers; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.common.utils.SearchHelper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.learning.services.connectors.WebServiceConnector; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.Transient; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -/** - * RESTSymbolAction to check if the request body of the last request has a JSON Attribute with a specific value. - */ -@Entity -@DiscriminatorValue("rest_checkAttributeValue") -@JsonTypeName("rest_checkAttributeValue") -public class CheckAttributeValueAction extends RESTSymbolAction { - - /** The name of the attribute to check for. */ - @NotBlank - private String attribute; - - /** The expected value of the attribute. */ - @NotBlank - @Column(name = "\"value\"") - private String value; - - /** Field to determine if the search string is a regular expression. */ - @NotNull - @Column(name = "\"regexp\"") - private boolean regexp; - - @Override - public ExecuteResult execute(WebServiceConnector target) { - String body = target.getBody(); - String valueInTheBody = JSONHelpers.getAttributeValue(body, getAttributeWithVariableValues()); - - boolean result = valueInTheBody != null - && SearchHelper.search(getValueWithVariableValues(), valueInTheBody, regexp); - - logger.info(LoggerMarkers.LEARNER, "Check if the attribute '{}' has the value '{}' in '{}' => {} (regexp: {}).", - attribute, value, body, result, regexp); - if (result) { - return getSuccessOutput(); - } else { - return getFailedOutput(); - } - } - - public String getAttribute() { - return attribute; - } - - /** - * Get the field name of the requested attribute. All variables and counters will be replaced with their values. - * - * @return The name of the attribute. - */ - @Transient - @JsonIgnore - public String getAttributeWithVariableValues() { - return insertVariableValues(attribute); - } - - public void setAttribute(String attribute) { - this.attribute = attribute; - } - - public String getValue() { - return value; - } - - /** - * Get the expected value of the attribute. All variables and counters will be replaced with their values. - * - * @return The expected attribute value. - */ - @Transient - @JsonIgnore - public String getValueWithVariableValues() { - return insertVariableValues(value); - } - - public void setValue(String value) { - this.value = value; - } - - public boolean isRegexp() { - return regexp; - } - - public void setRegexp(boolean regexp) { - this.regexp = regexp; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CheckHeaderFieldAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CheckHeaderFieldAction.java deleted file mode 100644 index 1e4fe3237..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CheckHeaderFieldAction.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.rest; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.common.utils.SearchHelper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.learning.services.connectors.WebServiceConnector; -import java.util.List; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.Transient; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -/** - * RESTSymbolAction to check the HTTP Header fields of the last request. - */ -@Entity -@DiscriminatorValue("rest_checkHeaderField") -@JsonTypeName("rest_checkHeaderField") -public class CheckHeaderFieldAction extends RESTSymbolAction { - - /** The key of the header field to check for the value. */ - @NotBlank - @Column(name = "\"key\"") - private String key; - - /** The expected value which should be in the header field. */ - @NotBlank - @Column(name = "\"value\"") - private String value; - - /** Field to determine if the search string is a regular expression. */ - @NotNull - @Column(name = "\"regexp\"") - private boolean regexp; - - @Override - public ExecuteResult execute(WebServiceConnector connector) { - List headerFieldValues = connector.getHeaders().get(key); - if (headerFieldValues == null) { - logger.info(LoggerMarkers.LEARNER, "Could header {} against the value {}, because the header was not found (regExp: {}).", - key, value, regexp); - return getFailedOutput(); - } - - boolean result; - if (regexp) { - result = searchWithRegex(headerFieldValues); - } else { - result = search(headerFieldValues); - } - - logger.info(LoggerMarkers.LEARNER, "Checked header {} with the value {} against {} => {} (regExp: {}).", - key, headerFieldValues, value, result, regexp); - if (result) { - return getSuccessOutput(); - } else { - return getFailedOutput(); - } - } - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - public String getValue() { - return value; - } - - /** - * Get the expected value of the header field. All variables and counters will be replaced with their values. - * - * @return The value to search for. - */ - @Transient - @JsonIgnore - public String getValueWithVariableValues() { - return insertVariableValues(value); - } - - public void setValue(String value) { - this.value = value; - } - - public boolean isRegexp() { - return regexp; - } - - public void setRegexp(boolean regexp) { - this.regexp = regexp; - } - - private boolean search(List headerFieldValues) { - return headerFieldValues.contains(getValueWithVariableValues()); - } - - private boolean searchWithRegex(List headerFieldValues) { - for (Object headerFieldValue : headerFieldValues) { - String headerFieldValueAsString = headerFieldValue.toString(); - if (SearchHelper.searchWithRegex(getValueWithVariableValues(), headerFieldValueAsString)) { - return true; - } - } - return false; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CheckStatusAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CheckStatusAction.java deleted file mode 100644 index d7e661445..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CheckStatusAction.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.rest; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.learning.services.connectors.WebServiceConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; - -/** - * RESTSymbolAction to check if the last call returned a specific status code. - */ -@Entity -@DiscriminatorValue("rest_checkStatus") -@JsonTypeName("rest_checkStatus") -public class CheckStatusAction extends RESTSymbolAction { - - /** The smallest possible HTTP status. */ - private static final int MIN_HTTP_STATUS = 100; - - /** The status code to check. */ - @NotNull - @Min(MIN_HTTP_STATUS) - private int status; - - @Override - public ExecuteResult execute(WebServiceConnector target) { - int returnedStatus = target.getStatus(); - - boolean result = this.status == returnedStatus; - - logger.info(LoggerMarkers.LEARNER, "Checked if the returned status code '{}' is equal to '{}' => {}.", - returnedStatus, status, result); - if (result) { - return getSuccessOutput(); - } else { - return getFailedOutput(); - } - } - - public int getStatus() { - return status; - } - - public void setStatus(int status) { - this.status = status; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CheckTextRestAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CheckTextRestAction.java deleted file mode 100644 index 4c00337e5..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/CheckTextRestAction.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.rest; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.common.utils.SearchHelper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.learning.services.connectors.WebServiceConnector; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.Transient; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -/** - * RESTSymbolAction to check if the response body of the last request contains a certain text. - */ -@Entity -@DiscriminatorValue("rest_checkForText") -@JsonTypeName("rest_checkForText") -public class CheckTextRestAction extends RESTSymbolAction { - - /** The expected text in the response body of the last request. */ - @NotBlank - @Column(name = "\"value\"") - private String value; - - /** Field to determine if the search string is a regular expression. */ - @NotNull - @Column(name = "\"regexp\"") - private boolean regexp; - - @Override - public ExecuteResult execute(WebServiceConnector target) { - String body = target.getBody(); - boolean result = SearchHelper.search(getValueWithVariableValues(), body, regexp); - - logger.info(LoggerMarkers.LEARNER, "Check if the value '{}' is in '{}' => {} (regexp: {}).", - value, body, result, regexp); - if (result) { - return getSuccessOutput(); - } else { - return getFailedOutput(); - } - } - - public String getValue() { - return value; - } - - /** - * Get the value which should be in the body of the last request. All variables and counters will be replaced with - * their values. - * - * @return The value to search for. - */ - @Transient - @JsonIgnore - public String getValueWithVariableValues() { - return insertVariableValues(value); - } - - public void setValue(String value) { - this.value = value; - } - - public boolean isRegexp() { - return regexp; - } - - public void setRegexp(boolean regexp) { - this.regexp = regexp; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/RESTSymbolAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/RESTSymbolAction.java deleted file mode 100644 index cbb28eb34..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/RESTSymbolAction.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.rest; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.WebServiceConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; - -/** - * Base class for all the REST specific actions. - */ -@Entity -@DiscriminatorValue("rest") -@JsonTypeName("rest") -public abstract class RESTSymbolAction extends SymbolAction { - - @Override - public ExecuteResult execute(ConnectorManager connector) { - return execute(connector.getConnector(WebServiceConnector.class)); - } - - /** - * Execute a REST action, i.e. a action that interacts with an web service interface. - * - * @param connector - * The connector to connect to web services. - * @return An indicator of the action was executed successfully or not. - */ - protected abstract ExecuteResult execute(WebServiceConnector connector); - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/ValidateJsonAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/ValidateJsonAction.java deleted file mode 100644 index 9612332af..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/rest/ValidateJsonAction.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.rest; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.fge.jsonschema.core.exceptions.ProcessingException; -import com.github.fge.jsonschema.core.report.ProcessingReport; -import com.github.fge.jsonschema.main.JsonSchemaFactory; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.learning.services.connectors.WebServiceConnector; -import java.io.IOException; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.NotBlank; - -/** - * Validates a JSON object against a JSON schema v4. See https://tools.ietf.org/html/draft-zyp-json-schema-04. - */ -@Entity -@DiscriminatorValue("rest_validateJson") -@JsonTypeName("rest_validateJson") -public class ValidateJsonAction extends RESTSymbolAction { - - /** - * The JSON schema to validate the response of the latest request against. - */ - @NotBlank - @Column(name = "\"schema\"", columnDefinition = "TEXT") - private String schema; - - @Override - protected ExecuteResult execute(final WebServiceConnector connector) { - final String body = connector.getBody(); - final ObjectMapper mapper = new ObjectMapper(); - - try { - final JsonNode obj = mapper.readTree(body); - final JsonNode jsonSchema = mapper.readTree(this.schema); - - final ProcessingReport report = JsonSchemaFactory.byDefault() - .getJsonSchema(jsonSchema) - .validate(obj); - - final ExecuteResult result = report.isSuccess() ? getSuccessOutput() : getFailedOutput(); - logger.info(LoggerMarkers.LEARNER, "Validated JSON document with {}", result); - return result; - } catch (IOException | ProcessingException e) { - logger.info(LoggerMarkers.LEARNER, "Failed to validate JSON document."); - return getFailedOutput(); - } - } - - public String getSchema() { - return schema; - } - - public void setSchema(String schema) { - this.schema = schema; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/AlertAcceptDismissAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/AlertAcceptDismissAction.java deleted file mode 100644 index 1c4fbfebf..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/AlertAcceptDismissAction.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.Alert; -import org.openqa.selenium.NoAlertPresentException; - -/** - * Accepts or dismisses the current window alert. - */ -@Entity -@DiscriminatorValue("web_alertAcceptDismiss") -@JsonTypeName("web_alertAcceptDismiss") -public class AlertAcceptDismissAction extends WebSymbolAction { - - /** The actions for an alert. */ - public enum Action { - - /** If the alert should be accepted. */ - ACCEPT, - - /** If the alert should be dismissed. */ - DISMISS - } - - /** The action to take with the alert. */ - @NotNull - private Action action; - - /** Constructor. */ - public AlertAcceptDismissAction() { - this.action = Action.DISMISS; - } - - @Override - protected ExecuteResult execute(final WebSiteConnector connector) { - try { - final Alert alert = connector.getDriver().switchTo().alert(); - - if (this.action == Action.ACCEPT) { - alert.accept(); - logger.info(LoggerMarkers.LEARNER, "Accept alert window."); - } else { - alert.dismiss(); - logger.info(LoggerMarkers.LEARNER, "Dismiss alert window."); - } - - return getSuccessOutput(); - } catch (NoAlertPresentException e) { - logger.info(LoggerMarkers.LEARNER, "Failed accept or dismiss alert window."); - return getFailedOutput(); - } - } - - public Action getAction() { - return action; - } - - public void setAction(Action action) { - this.action = action; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/AlertGetTextAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/AlertGetTextAction.java deleted file mode 100644 index b7fb0e133..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/AlertGetTextAction.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.NotBlank; -import org.openqa.selenium.Alert; -import org.openqa.selenium.NoAlertPresentException; - -/** - * Saves the displayed text of a window.alert, window.confirm and window.prompt alert in a variable. - */ -@Entity -@DiscriminatorValue("web_alertGetText") -@JsonTypeName("web_alertGetText") -public class AlertGetTextAction extends SymbolAction { - - /** The name of the variable to store the displayed text of the alert in. */ - @NotBlank - private String variableName; - - @Override - public ExecuteResult execute(final ConnectorManager connector) { - final VariableStoreConnector variableStore = connector.getConnector(VariableStoreConnector.class); - final WebSiteConnector webSiteConnector = connector.getConnector(WebSiteConnector.class); - - try { - final Alert alert = webSiteConnector.getDriver().switchTo().alert(); - final String text = alert.getText(); - variableStore.set(variableName, text); - - logger.info(LoggerMarkers.LEARNER, "Save text '{}' from alert to variable '{}'.", text, variableName); - return getSuccessOutput(); - } catch (NoAlertPresentException e) { - logger.info(LoggerMarkers.LEARNER, "Failed to get text from alert."); - return getFailedOutput(); - } - } - - public String getVariableName() { - return variableName; - } - - public void setVariableName(String variableName) { - this.variableName = variableName; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/AlertSendKeysAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/AlertSendKeysAction.java deleted file mode 100644 index 2faba4377..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/AlertSendKeysAction.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.Alert; - -/** - * Sends text to a prompt alert from window.prompt("..."). - */ -@Entity -@DiscriminatorValue("web_alertSendKeys") -@JsonTypeName("web_alertSendKeys") -public class AlertSendKeysAction extends WebSymbolAction { - - /** The text to send to the prompt alert. */ - @NotNull - private String text; - - @Override - protected ExecuteResult execute(final WebSiteConnector connector) { - try { - final Alert alert = connector.getDriver().switchTo().alert(); - alert.sendKeys(insertVariableValues(text)); - alert.accept(); - - logger.info(LoggerMarkers.LEARNER, "Send text '{}' to prompt window.", text); - return getSuccessOutput(); - } catch (Exception e) { - logger.info(LoggerMarkers.LEARNER, "Failed to send text '{}' to prompt window.", text); - return getFailedOutput(); - } - } - - public String getText() { - return text; - } - - public void setText(String text) { - this.text = text; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/BrowserAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/BrowserAction.java deleted file mode 100644 index d1cefbf70..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/BrowserAction.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WindowType; - -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.NotNull; - -/** Action for doing something with the browser window. */ -@Entity -@DiscriminatorValue("web_browser") -@JsonTypeName("web_browser") -public class BrowserAction extends WebSymbolAction { - - /** What to do with the open browser window. */ - public enum Action { - - /** If the browser should be restarted. */ - RESTART, - - /** If the browser window should be refreshed. */ - REFRESH, - - /** Create a new tab in the browser. */ - CREATE_TAB, - - /** Create a new browser window. */ - CREATE_WINDOW, - - /** Close the active tab. */ - CLOSE_TAB, - - /** Close the active window. */ - CLOSE_WINDOW - } - - /** The action to execute on the browser window. */ - @Column(name = "browser_action") - @NotNull - private Action action; - - /** Constructor. */ - public BrowserAction() { - this.action = Action.RESTART; - } - - @Override - protected ExecuteResult execute(WebSiteConnector connector) { - try { - final var wd = connector.getDriver(); - switch (action) { - case RESTART -> { - logger.info(LoggerMarkers.LEARNER, "Restart browser."); - connector.restart(); - } - case REFRESH -> { - logger.info(LoggerMarkers.LEARNER, "Refresh browser."); - connector.refresh(); - } - case CREATE_TAB -> { - logger.info(LoggerMarkers.LEARNER, "Create a new tab."); - wd.switchTo().newWindow(WindowType.TAB); - } - case CREATE_WINDOW -> { - logger.info(LoggerMarkers.LEARNER, "Create a new window."); - wd.switchTo().newWindow(WindowType.WINDOW); - } - case CLOSE_TAB -> { - logger.info(LoggerMarkers.LEARNER, "Close the active tab."); - switchToMainWindow(wd); - } - case CLOSE_WINDOW -> { - logger.info(LoggerMarkers.LEARNER, "Close the active window."); - switchToMainWindow(wd); - } - default -> throw new Exception("Invalid browser action."); - } - return getSuccessOutput(); - } catch (Exception e) { - logger.info(LoggerMarkers.LEARNER, "Browser action could not be performed.", e); - return getFailedOutput(); - } - } - - public Action getAction() { - return action; - } - - public void setAction(Action action) { - this.action = action; - } - - private void switchToMainWindow(WebDriver wd) { - wd.close(); - final var mainHandle = wd.getWindowHandles().iterator().next(); - wd.switchTo().window(mainHandle); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/CheckNodeAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/CheckNodeAction.java deleted file mode 100644 index 973b4975a..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/CheckNodeAction.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.NoSuchElementException; - -/** - * Action to check for a specific element/ a specific text. - */ -@Entity -@DiscriminatorValue("web_checkForNode") -@JsonTypeName("web_checkForNode") -public class CheckNodeAction extends WebSymbolAction { - - /** The node on the site that is checked for. */ - @NotNull - @Embedded - private WebElementLocator node; - - @Override - public ExecuteResult execute(WebSiteConnector connector) { - final WebElementLocator nodeWithVariables = - new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - - try { - connector.getElement(nodeWithVariables); - - logger.info(LoggerMarkers.LEARNER, "Found element '{}'.", nodeWithVariables); - return getSuccessOutput(); - } catch (NoSuchElementException e) { - logger.info(LoggerMarkers.LEARNER, "Could not find element '{}'.", nodeWithVariables, e); - return getFailedOutput(); - } - } - - public WebElementLocator getNode() { - return node; - } - - public void setNode(WebElementLocator node) { - this.node = node; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/CheckNodeAttributeValueAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/CheckNodeAttributeValueAction.java deleted file mode 100644 index 3b7c8a731..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/CheckNodeAttributeValueAction.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; - -/** - * Action to check the value of a nodes attribute. - */ -@Entity -@DiscriminatorValue("web_checkNodeAttributeValue") -@JsonTypeName("web_checkNodeAttributeValue") -public class CheckNodeAttributeValueAction extends WebSymbolAction { - - /** - * Enumeration to specify the check method. - */ - public enum CheckMethod { - - /** - * If the attribute contains the value. - */ - CONTAINS, - - /** - * If the attribute exists. - */ - EXISTS, - - /** - * If the attribute equals the value. - */ - IS, - - /** - * If the attribute matches the value. - */ - MATCHES; - - /** - * Parser function to handle the enum names case insensitive. - * - * @param name - * The enum name. - * @return The corresponding CheckMethod. - * @throws IllegalArgumentException - * If the name could not be parsed. - */ - @JsonCreator - public static CheckMethod fromString(String name) throws IllegalArgumentException { - return CheckMethod.valueOf(name.toUpperCase()); - } - - @Override - public String toString() { - return name().toLowerCase(); - } - } - - /** - * The selector of the element. - */ - @NotNull - @Embedded - private WebElementLocator node; - - /** - * The attribute name of the element to check. - */ - @NotBlank - private String attribute; - - /** - * The attribute value to check for. - */ - @NotNull - @Column(name = "\"value\"") - private String value; - - /** - * The method that is used to check the attribute value. - */ - @NotNull - private CheckMethod checkMethod; - - @Override - protected ExecuteResult execute(WebSiteConnector connector) { - final WebElementLocator nodeWithVariables = - new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - - final String valueWithVariables = insertVariableValues(value); - - try { - final WebElement element = connector.getElement(nodeWithVariables); - final String attributeValue = element.getAttribute(attribute); - - if (attributeValue == null) { - logger.info(LoggerMarkers.LEARNER, "Attribute '{}' not found on element '{}'", - attribute, nodeWithVariables); - return getFailedOutput(); - } - - boolean isValid = false; - switch (checkMethod) { - case IS: - isValid = attributeValue.equals(valueWithVariables); - break; - case EXISTS: - // since the case that the attribute does not exist is checked above, we can set this to true. - isValid = true; - break; - case CONTAINS: - isValid = attributeValue.contains(valueWithVariables); - break; - case MATCHES: - isValid = attributeValue.matches(valueWithVariables); - break; - default: - break; - } - - if (isValid) { - logger.info(LoggerMarkers.LEARNER, "The value of the attribute '{}' of the node '{}'" - + " '{}' the searched value '{}'.", - attribute, nodeWithVariables, checkMethod, valueWithVariables); - return getSuccessOutput(); - } else { - logger.info(LoggerMarkers.LEARNER, "The value of the attribute '{}' of the node '{}'" - + " does not '{}' the searched value '{}'.", - attribute, nodeWithVariables, checkMethod, valueWithVariables); - return getFailedOutput(); - } - } catch (NoSuchElementException e) { - logger.info(LoggerMarkers.LEARNER, "Could not find the node '{}'.", nodeWithVariables, e); - return getFailedOutput(); - } - } - - public WebElementLocator getNode() { - return node; - } - - public void setNode(WebElementLocator node) { - this.node = node; - } - - public String getAttribute() { - return attribute; - } - - public void setAttribute(String attribute) { - this.attribute = attribute; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - public CheckMethod getCheckMethod() { - return checkMethod; - } - - public void setCheckMethod(CheckMethod checkMethod) { - this.checkMethod = checkMethod; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/CheckNodeSelectedAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/CheckNodeSelectedAction.java deleted file mode 100644 index 05cc71faf..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/CheckNodeSelectedAction.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; - -/** - * Action to assert that an input[type="radio"] or input[type="checkbox"] is selected. - */ -@Entity -@DiscriminatorValue("web_checkNodeSelected") -@JsonTypeName("web_checkNodeSelected") -public class CheckNodeSelectedAction extends WebSymbolAction { - - /** The input element. */ - @NotNull - private WebElementLocator node; - - @Override - protected ExecuteResult execute(WebSiteConnector connector) { - final WebElementLocator nodeWithVariables = - new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - - try { - final WebElement element = connector.getElement(nodeWithVariables); - if (element.isSelected()) { - logger.info(LoggerMarkers.LEARNER, "Element '{}' is selected.", nodeWithVariables); - return getSuccessOutput(); - } else { - logger.info(LoggerMarkers.LEARNER, "Element '{}' is not selected.", nodeWithVariables); - return getFailedOutput(); - } - } catch (NoSuchElementException e) { - logger.info(LoggerMarkers.LEARNER, "Could not assert if element '{}' is selected ", nodeWithVariables); - return getFailedOutput(); - } - } - - public WebElementLocator getNode() { - return node; - } - - public void setNode(WebElementLocator node) { - this.node = node; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/CheckPageTitleAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/CheckPageTitleAction.java deleted file mode 100644 index 888bea5f7..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/CheckPageTitleAction.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.common.utils.SearchHelper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.Transient; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.WebDriver; - -/** - * Action to check the page title. - */ -@Entity -@DiscriminatorValue("web_checkPageTitle") -@JsonTypeName("web_checkPageTitle") -public class CheckPageTitleAction extends WebSymbolAction { - - /** The title of the web page. */ - @NotBlank - private String title; - - /** - * Field to determine if the search string is a regular expression. Only works while searching for text. - */ - @NotNull - @Column(name = "\"regexp\"") - private boolean regexp; - - /** Constructor. */ - public CheckPageTitleAction() { - this.regexp = false; - } - - @Override - public ExecuteResult execute(WebSiteConnector connector) { - final WebDriver driver = connector.getDriver(); - final boolean result = SearchHelper.search(getTitleWithVariableValues(), driver.getTitle(), regexp); - - logger.info(LoggerMarkers.LEARNER, "Check if the current page has title '{}' => {} (regExp: {}).", - title, result, regexp); - - return result ? getSuccessOutput() : getFailedOutput(); - } - - public String getTitle() { - return title; - } - - /** - * Get the title to check. All variables and counters will be replaced with their values. - * - * @return The title to check. - */ - @Transient - @JsonIgnore - public String getTitleWithVariableValues() { - return insertVariableValues(title); - } - - public void setTitle(String title) { - this.title = title; - } - - public boolean isRegexp() { - return regexp; - } - - public void setRegexp(boolean regexp) { - this.regexp = regexp; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/CheckTextWebAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/CheckTextWebAction.java deleted file mode 100644 index 8c353b2dd..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/CheckTextWebAction.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.common.utils.SearchHelper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.persistence.Transient; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import org.apache.commons.text.StringEscapeUtils; -import org.openqa.selenium.NoSuchElementException; - -/** - * Action to check for a specific element/ a specific text. - */ -@Entity -@DiscriminatorValue("web_checkForText") -@JsonTypeName("web_checkForText") -public class CheckTextWebAction extends WebSymbolAction { - - /** The value the site is checked for. */ - @NotBlank - @Column(name = "\"value\"") - private String value; - - /** - * Field to determine if the search string is a regular expression. Only works while searching for text. - */ - @NotNull - @Column(name = "\"regexp\"") - private boolean regexp; - - /** - * Search for text in a specific element. - */ - @NotNull - @Embedded - private WebElementLocator node; - - /** - * Constructor. - */ - public CheckTextWebAction() { - this.regexp = false; - this.node = new WebElementLocator("document", WebElementLocator.Type.CSS); - } - - @Override - public ExecuteResult execute(WebSiteConnector connector) { - final WebElementLocator nodeWithVariables = - new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - - try { - final String source; - if (nodeWithVariables.getSelector().equals("document")) { - source = connector.getDriver().getPageSource(); - } else { - source = connector.getElement(nodeWithVariables).getAttribute("innerHTML"); - } - - final String htmlEscapedValue = StringEscapeUtils.escapeHtml4(getValueWithVariableValues()); - final boolean found = SearchHelper.search(htmlEscapedValue, source, regexp); - - logger.info(LoggerMarkers.LEARNER, "Check if the current pages contains '{}' => {} (regExp: {}).", - value, found, regexp); - - return found ? getSuccessOutput() : getFailedOutput(); - } catch (NoSuchElementException e) { - logger.error(LoggerMarkers.LEARNER, "Could not find text '{}' in element '{}' (regExp: {}).", - value, node.getSelector(), regexp); - return getFailedOutput(); - } catch (Exception e) { - logger.error(LoggerMarkers.LEARNER, "Failed to search for text '{}' in element '{}' (regExp: {}).", - value, node.getSelector(), regexp, e); - return getFailedOutput(); - } - } - - public String getValue() { - return value; - } - - @JsonIgnore - @Transient - public String getValueWithVariableValues() { - return insertVariableValues(value); - } - - public void setValue(String value) { - this.value = value; - } - - public boolean isRegexp() { - return regexp; - } - - public void setRegexp(boolean regexp) { - this.regexp = regexp; - } - - public WebElementLocator getNode() { - return node; - } - - public void setNode(WebElementLocator node) { - this.node = node; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/ClearAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/ClearAction.java deleted file mode 100644 index 86d7be1bf..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/ClearAction.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import org.openqa.selenium.Keys; - -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.validation.constraints.NotNull; - -/** - * Action to clear on a specific element. - */ -@Entity -@DiscriminatorValue("web_clear") -@JsonTypeName("web_clear") -public class ClearAction extends WebSymbolAction { - - /** The node to look for. */ - @NotNull - @Embedded - private WebElementLocator node; - - @Override - public ExecuteResult execute(WebSiteConnector connector) { - final WebElementLocator nodeWithVariables = - new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - - try { - connector.getElement(nodeWithVariables).sendKeys(Keys.chord(Keys.CONTROL, "a", Keys.DELETE)); - - logger.info(LoggerMarkers.LEARNER, "Cleared element '{}'.", nodeWithVariables); - return getSuccessOutput(); - } catch (Exception e) { - logger.info(LoggerMarkers.LEARNER, "Could not clear element '{}'.", nodeWithVariables, e); - return getFailedOutput(); - } - } - - public WebElementLocator getNode() { - return node; - } - - public void setNode(WebElementLocator node) { - this.node = node; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/ClickAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/ClickAction.java deleted file mode 100644 index e50c22230..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/ClickAction.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.interactions.Actions; - -/** - * Action to click on a specific element. - */ -@Entity -@DiscriminatorValue("web_click") -@JsonTypeName("web_click") -public class ClickAction extends WebSymbolAction { - - /** - * The information to identify the element. - */ - @NotNull - @Embedded - private WebElementLocator node; - - /** - * If a double click is executed. - */ - @NotNull - private boolean doubleClick; - - /** Constructor. */ - public ClickAction() { - doubleClick = false; - } - - @Override - public ExecuteResult execute(WebSiteConnector connector) { - final WebElementLocator nodeWithVariables = - new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - - try { - final WebElement element = connector.getElement(nodeWithVariables); - - if (doubleClick) { - new Actions(connector.getDriver()).doubleClick(element).build().perform(); - } else { - element.click(); - } - - logger.info(LoggerMarkers.LEARNER, "Clicked on element '{}' (doubleClick: {}).", - nodeWithVariables, doubleClick); - return getSuccessOutput(); - } catch (NoSuchElementException e) { - logger.info(LoggerMarkers.LEARNER, "Could not find element '{}' (doubleClick: {}).", - nodeWithVariables, doubleClick); - } catch (Exception e) { - logger.info(LoggerMarkers.LEARNER, "Failed to click on element '{}' (doubleClick: {}).", - nodeWithVariables, doubleClick, e); - } - - return getFailedOutput(); - } - - public WebElementLocator getNode() { - return node; - } - - public boolean isDoubleClick() { - return doubleClick; - } - - public void setDoubleClick(boolean doubleClick) { - this.doubleClick = doubleClick; - } - - public void setNode(WebElementLocator node) { - this.node = node; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/ClickElementByTextAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/ClickElementByTextAction.java deleted file mode 100644 index 40b8b556b..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/ClickElementByTextAction.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import java.util.List; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.By; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; - -/** - * Action to click a specific element by its visible text. - */ -@Entity -@DiscriminatorValue("web_clickElementByText") -@JsonTypeName("web_clickElementByText") -public class ClickElementByTextAction extends WebSymbolAction { - - /** Search link in a specific element. */ - @NotNull - @Embedded - private WebElementLocator node; - - /** The tag name of the node, e.g. "button". */ - private String tagName; - - /** The visible text of the element. */ - @NotBlank - private String text; - - /** Constructor. */ - public ClickElementByTextAction() { - this.node = new WebElementLocator("body", WebElementLocator.Type.CSS); - } - - @Override - protected ExecuteResult execute(WebSiteConnector connector) { - final WebElementLocator nodeWithVariables = - new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - - final WebElement root = connector.getElement(nodeWithVariables); - final String textWithVariables = insertVariableValues(text); - - final List candidates; - if (tagName == null || tagName.trim().equals("")) { - candidates = root.findElements(By.xpath("//*[text()[normalize-space() = '" + textWithVariables + "']]")); - } else { - candidates = root.findElements(By.tagName(tagName)); - } - - try { - if (candidates.isEmpty()) { - throw new NoSuchElementException("No candidate with text '" + textWithVariables + "' found."); - } - - for (final WebElement candidate : candidates) { - final boolean hasText = candidate.getText().trim().equals(textWithVariables); - if (candidate.isDisplayed() && candidate.isEnabled() && hasText) { - candidate.click(); - - logger.info(LoggerMarkers.LEARNER, "Click on element '{}' with text '{}' ", tagName, text); - return getSuccessOutput(); - } - } - throw new NoSuchElementException("No clickable element found."); - } catch (Exception e) { - logger.info(LoggerMarkers.LEARNER, "Could not click on element '{}' with text '{}' ", tagName, text, e); - return getFailedOutput(); - } - } - - public WebElementLocator getNode() { - return node; - } - - public void setNode(WebElementLocator node) { - this.node = node; - } - - public String getTagName() { - return tagName; - } - - public void setTagName(String tagName) { - this.tagName = tagName; - } - - public String getText() { - return text; - } - - public void setText(String text) { - this.text = text; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/ClickLinkAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/ClickLinkAction.java deleted file mode 100644 index 18ab96fa1..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/ClickLinkAction.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.persistence.Transient; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.By; -import org.openqa.selenium.WebElement; - -/** - * Action to click on a link by its visible link. - */ -@Entity -@DiscriminatorValue("web_clickLinkByText") -@JsonTypeName("web_clickLinkByText") -public class ClickLinkAction extends WebSymbolAction { - - /** The value the site is checked for. */ - @NotBlank - @Column(name = "\"value\"") - private String value; - - /** - * Search link in a specific element. - */ - @NotNull - @Embedded - private WebElementLocator node; - - /** - * Constructor. - */ - public ClickLinkAction() { - this.node = new WebElementLocator("body", WebElementLocator.Type.CSS); - } - - @Override - public ExecuteResult execute(WebSiteConnector connector) { - final WebElementLocator nodeWithVariables = - new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - - try { - final String linkText = getValueWithVariableValues(); - - final WebElement element = connector.getElement(nodeWithVariables) - .findElement(By.linkText(linkText)); - - element.click(); - - logger.info(LoggerMarkers.LEARNER, "Clicked on link '{}'.", value); - return getSuccessOutput(); - } catch (Exception e) { - logger.info(LoggerMarkers.LEARNER, "Could not click on link '{}'.", value, e); - return getFailedOutput(); - } - } - - public String getValue() { - return value; - } - - /** - * Get the value to check. All variables and counters will be replaced with their values. - * - * @return The value to check. - */ - @Transient - @JsonIgnore - public String getValueWithVariableValues() { - return insertVariableValues(value); - } - - public void setValue(String value) { - this.value = value; - } - - public WebElementLocator getNode() { - return node; - } - - public void setNode(WebElementLocator node) { - this.node = node; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/DragAndDropAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/DragAndDropAction.java deleted file mode 100644 index 9299d4039..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/DragAndDropAction.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.AttributeOverride; -import javax.persistence.AttributeOverrides; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.interactions.Actions; - -@Entity -@DiscriminatorValue("web_dragAndDrop") -@JsonTypeName("web_dragAndDrop") -public class DragAndDropAction extends WebSymbolAction { - - @NotNull - @Embedded - @AttributeOverrides({ - @AttributeOverride(name = "selector", column = @Column(name = "DND_SOURCE_NODE_SELECTOR")), - @AttributeOverride(name = "type", column = @Column(name = "DND_SOURCE_NODE_TYPE")) - }) - private WebElementLocator sourceNode; - - @NotNull - @Embedded - @AttributeOverrides({ - @AttributeOverride(name = "selector", column = @Column(name = "DND_TARGET_NODE_SELECTOR")), - @AttributeOverride(name = "type", column = @Column(name = "DND_TARGET_NODE_TYPE")) - }) - private WebElementLocator targetNode; - - @Override - protected ExecuteResult execute(WebSiteConnector connector) { - final WebElementLocator sourceNodeWithVariables = - new WebElementLocator(insertVariableValues(sourceNode.getSelector()), sourceNode.getType()); - - final WebElementLocator targetNodeWithVariables = - new WebElementLocator(insertVariableValues(targetNode.getSelector()), targetNode.getType()); - - try { - final WebElement source = connector.getElement(sourceNodeWithVariables); - final WebElement target = connector.getElement(targetNodeWithVariables); - new Actions(connector.getDriver()).dragAndDrop(source, target).build().perform(); - logger.info(LoggerMarkers.LEARNER, "Drag element '({})' to element '({})'.", source, target); - return getSuccessOutput(); - } catch (NoSuchElementException e) { - logger.info(LoggerMarkers.LEARNER, "Could not perform drag and drop"); - return getFailedOutput(); - } - } - - public WebElementLocator getSourceNode() { - return sourceNode; - } - - public void setSourceNode(WebElementLocator sourceNode) { - this.sourceNode = sourceNode; - } - - public WebElementLocator getTargetNode() { - return targetNode; - } - - public void setTargetNode(WebElementLocator targetNode) { - this.targetNode = targetNode; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/DragAndDropByAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/DragAndDropByAction.java deleted file mode 100644 index cae163a56..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/DragAndDropByAction.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.AttributeOverride; -import javax.persistence.AttributeOverrides; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.interactions.Actions; - -@Entity -@DiscriminatorValue("web_dragAndDropBy") -@JsonTypeName("web_dragAndDropBy") -public class DragAndDropByAction extends WebSymbolAction { - - @NotNull - @Embedded - @AttributeOverrides({ - @AttributeOverride(name = "selector", column = @Column(name = "DND_SOURCE_NODE_SELECTOR")), - @AttributeOverride(name = "type", column = @Column(name = "DND_SOURCE_NODE_TYPE")) - }) - private WebElementLocator sourceNode; - - @NotNull - private int offsetX; - - @NotNull - private int offsetY; - - public DragAndDropByAction() { - this.offsetX = 0; - this.offsetY = 0; - } - - @Override - protected ExecuteResult execute(WebSiteConnector connector) { - final WebElementLocator sourceNodeWithVariables = - new WebElementLocator(insertVariableValues(sourceNode.getSelector()), sourceNode.getType()); - - try { - final WebElement source = connector.getElement(sourceNodeWithVariables); - new Actions(connector.getDriver()).dragAndDropBy(source, offsetX, offsetY).build().perform(); - logger.info(LoggerMarkers.LEARNER, "Drag element '({})' by ({}, {}).", source, offsetX, offsetY); - return getSuccessOutput(); - } catch (NoSuchElementException e) { - logger.info(LoggerMarkers.LEARNER, "Could not perform drag and drop"); - return getFailedOutput(); - } - } - - public WebElementLocator getSourceNode() { - return sourceNode; - } - - public void setSourceNode(WebElementLocator sourceNode) { - this.sourceNode = sourceNode; - } - - public int getOffsetX() { - return offsetX; - } - - public void setOffsetX(int offsetX) { - this.offsetX = offsetX; - } - - public int getOffsetY() { - return offsetY; - } - - public void setOffsetY(int offsetY) { - this.offsetY = offsetY; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/ExecuteScriptAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/ExecuteScriptAction.java deleted file mode 100644 index 90ee7a4d8..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/ExecuteScriptAction.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.data.utils.ExecuteScriptUtils; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import java.time.Duration; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.JavascriptExecutor; -import org.openqa.selenium.WebElement; - -/** - * Action to execute JavaScript on the opened browser. - */ -@Entity -@DiscriminatorValue("web_executeScript") -@JsonTypeName("web_executeScript") -public class ExecuteScriptAction extends SymbolAction { - - /** How long in seconds should be waited before the script times out. */ - private static final int DEFAULT_SCRIPT_TIMEOUT = 10; - - /** The JavaScript to execute. */ - @NotBlank - @Column(columnDefinition = "TEXT") - private String script; - - /** If the script should be executed asynchronously. */ - @NotNull - private boolean async = false; - - /** When the script should be timed out in s. */ - @NotNull - @Min(value = 0) - private int timeout = DEFAULT_SCRIPT_TIMEOUT; - - /** The name of the variable to store the result into. */ - private String name; - - @Override - public ExecuteResult execute(ConnectorManager connector) { - WebSiteConnector webSiteConnector = connector.getConnector(WebSiteConnector.class); - VariableStoreConnector variableStore = connector.getConnector(VariableStoreConnector.class); - - if (webSiteConnector.getDriver() instanceof JavascriptExecutor) { - - final Map> store = ExecuteScriptUtils.createScriptStore(connector); - - try { - webSiteConnector.getDriver().manage().timeouts().scriptTimeout(Duration.ofSeconds(timeout)); - - final Object returnValue; - if (async) { - returnValue = ((JavascriptExecutor) webSiteConnector.getDriver()).executeAsyncScript(script, store); - } else { - returnValue = ((JavascriptExecutor) webSiteConnector.getDriver()).executeScript(script, store); - } - - if (name != null) { - if (returnValue == null) { - variableStore.set(name, "null"); - } else if (returnValue instanceof Double || returnValue instanceof Long - || returnValue instanceof Boolean) { - variableStore.set(name, String.valueOf(returnValue)); - } else if (returnValue instanceof WebElement || returnValue instanceof List) { - logger.info(LoggerMarkers.LEARNER, "WebElements and lists as return values are not supported."); - return getFailedOutput(); - } else { - variableStore.set(name, (String) returnValue); - } - } - - logger.info(LoggerMarkers.LEARNER, "JavaScript {} successfully executed."); - return getSuccessOutput(); - } catch (Exception e) { - logger.info(LoggerMarkers.LEARNER, "Could not execute JavaScript", e); - return getFailedOutput(); - } - } else { - logger.info(LoggerMarkers.LEARNER, "This driver does not support JavaScript!"); - return getFailedOutput(); - } - } - - public String getScript() { - return script; - } - - public void setScript(String script) { - this.script = script; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public boolean isAsync() { - return async; - } - - public void setAsync(boolean async) { - this.async = async; - } - - public int getTimeout() { - return timeout; - } - - public void setTimeout(int timeout) { - this.timeout = timeout; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/FillAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/FillAction.java deleted file mode 100644 index c18211712..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/FillAction.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.WebElement; - -/** - * Action to enter a text into a specific element. - */ -@Entity -@DiscriminatorValue("web_fill") -@JsonTypeName("web_fill") -public class FillAction extends WebSymbolAction { - - /** - * The node to look for. - */ - @NotNull - @Embedded - protected WebElementLocator node; - - /** - * The Value to insert. - */ - @NotBlank - @Column(name = "\"value\"") - protected String value; - - @Override - public ExecuteResult execute(WebSiteConnector connector) { - final WebElementLocator nodeWithVariables = - new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - - final String valueWithVariables = insertVariableValues(value); - try { - WebElement element = connector.getElement(nodeWithVariables); - element.sendKeys(valueWithVariables); - - logger.info("Filled the element '{}' with '{}'.", nodeWithVariables, value); - return getSuccessOutput(); - } catch (Exception e) { - logger.info(LoggerMarkers.LEARNER, "Could not find the element '{}' to fill it with '{}'", - nodeWithVariables, valueWithVariables, e); - return getFailedOutput(); - } - } - - public WebElementLocator getNode() { - return node; - } - - public void setNode(WebElementLocator node) { - this.node = node; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/GotoAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/GotoAction.java deleted file mode 100644 index e9e4d2c30..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/GotoAction.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.actions.Credentials; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.persistence.Transient; -import javax.validation.constraints.NotBlank; - -/** - * Action to navigate to a new URL. - */ -@Entity -@DiscriminatorValue("web_goto") -@JsonTypeName("web_goto") -public class GotoAction extends WebSymbolAction { - - /** - * The URL of the site. - * The URL can either be a path relative to the project's base URL or a absolute URL that starts with https?:// - */ - @NotBlank - private String url; - - @NotBlank - private String baseUrl; - - /** - * Optional credentials to authenticate via HTTP basic auth. - */ - @Embedded - private Credentials credentials; - - @Override - public ExecuteResult execute(WebSiteConnector connector) { - try { - connector.get(baseUrl, getURLWithVariableValues(), getCredentialsWithVariableValues()); - logger.info(LoggerMarkers.LEARNER, "Could goto '{}'.", url); - return getSuccessOutput(); - } catch (Exception e) { - logger.info(LoggerMarkers.LEARNER, "Could not goto '{}'.", url, e); - return getFailedOutput(); - } - } - - public String getUrl() { - return url; - } - - /** - * Get the URL this action will navigate to. All variables and counters will be replaced with their values. - * - * @return The site URL the element is on. - */ - @Transient - @JsonIgnore - public String getURLWithVariableValues() { - return insertVariableValues(url); - } - - public void setUrl(String url) { - this.url = url; - } - - public Credentials getCredentials() { - return credentials; - } - - /** - * Like {@link #getCredentials()}, but the name and password will have all variables and counters inserted. - * - * @return The credentials to use, with the actual values of counters and variables in their values. - */ - private Credentials getCredentialsWithVariableValues() { - if (credentials == null) { - return new Credentials(); - } - - String name = insertVariableValues(credentials.getName()); - String password = insertVariableValues(credentials.getPassword()); - - return new Credentials(name, password); - } - - public void setCredentials(Credentials credentials) { - this.credentials = credentials; - } - - public String getBaseUrl() { - return baseUrl; - } - - public void setBaseUrl(String baseUrl) { - this.baseUrl = baseUrl; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/MoveMouseAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/MoveMouseAction.java deleted file mode 100644 index fc1088a2a..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/MoveMouseAction.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.interactions.Actions; - -/** - * Action to move the mouse to an element or a screen position, e.g. in order to make invisible elements visible or to - * scroll on the page. - */ -@Entity -@DiscriminatorValue("web_moveMouse") -@JsonTypeName("web_moveMouse") -public class MoveMouseAction extends WebSymbolAction { - - /** - * The selector of the element. - */ - @Embedded - private WebElementLocator node; - - /** - * The amount in px to move the mouse in x direction from the current position. - */ - @NotNull - private int offsetX; - - /** - * The amount in px to move the mouse in y direction from the current position. - */ - @NotNull - private int offsetY; - - @Override - protected ExecuteResult execute(WebSiteConnector connector) { - final WebElementLocator nodeWithVariables = node == null ? null - : new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - - try { - final Actions actions = new Actions(connector.getDriver()); - - if (nodeWithVariables == null || nodeWithVariables.getSelector().trim().equals("")) { - actions.moveByOffset(offsetX, offsetY).build().perform(); - logger.info(LoggerMarkers.LEARNER, "Moved the mouse to the position ({}, {}) ", offsetX, offsetY); - } else { - final WebElement element = connector.getElement(nodeWithVariables); - actions.moveToElement(element, offsetX, offsetY).build().perform(); - logger.info(LoggerMarkers.LEARNER, "Moved the mouse to the element '{}'", nodeWithVariables); - } - - return getSuccessOutput(); - } catch (Exception e) { - logger.info(LoggerMarkers.LEARNER, "Could not move the mouse to the element '{}' or the position ({}, {})", - nodeWithVariables, offsetX, offsetY); - return getFailedOutput(); - } - } - - public int getOffsetY() { - return offsetY; - } - - public void setOffsetY(int offsetY) { - this.offsetY = offsetY; - } - - public WebElementLocator getNode() { - return node; - } - - public void setNode(WebElementLocator node) { - this.node = node; - } - - public int getOffsetX() { - return offsetX; - } - - public void setOffsetX(int offsetX) { - this.offsetX = offsetX; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/PressKeyAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/PressKeyAction.java deleted file mode 100644 index 469ef6338..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/PressKeyAction.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import org.apache.commons.text.StringEscapeUtils; -import org.openqa.selenium.Keys; -import org.openqa.selenium.WebElement; - -/** - * The action that simulates a key press. - */ -@Entity -@DiscriminatorValue("web_pressKey") -@JsonTypeName("web_pressKey") -public class PressKeyAction extends WebSymbolAction { - - /** - * The selector of the element. - */ - @NotNull - @Embedded - private WebElementLocator node; - - /** - * The escaped string representation of the unicode that represents the key. - **/ - @NotBlank - @Column(name = "\"key\"") - private String key; - - @Override - protected ExecuteResult execute(WebSiteConnector connector) { - final String unescapedKey = StringEscapeUtils.unescapeJava(this.key); - final Keys keyToPress = Keys.getKeyFromUnicode(unescapedKey.toCharArray()[0]); - - final WebElementLocator nodeWithVariables = - new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - - try { - final WebElement element = connector.getElement(nodeWithVariables); - element.sendKeys(keyToPress); - logger.info(LoggerMarkers.LEARNER, "Pressed the key '{}' on the element '{}'.", - keyToPress.toString(), nodeWithVariables); - return getSuccessOutput(); - } catch (Exception e) { - logger.info(LoggerMarkers.LEARNER, "Could not press key '{}' on element '{}'.", - keyToPress.toString(), nodeWithVariables, e); - return getFailedOutput(); - } - } - - public WebElementLocator getNode() { - return node; - } - - public void setNode(WebElementLocator node) { - this.node = node; - } - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/SelectAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/SelectAction.java deleted file mode 100644 index 9ed867c39..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/SelectAction.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.ui.Select; -import org.openqa.selenium.support.ui.UnexpectedTagNameException; - -/** - * Action to select an entry from a select field by its value. - */ -@Entity -@DiscriminatorValue("web_select") -@JsonTypeName("web_select") -public class SelectAction extends FillAction { - - /** - * Enum to choose how to interact with the selection input. - */ - public enum SelectByType { - - /** Select by the value attribute. */ - VALUE, - - /** Select by the option text. */ - TEXT, - - /** Select simply by using the index starting at 0. */ - INDEX; - - /** - * Parser function to handle the enum names case insensitive. - * - * @param name - * The enum name. - * @return The corresponding SelectByType. - * @throws IllegalArgumentException - * If the name could not be parsed. - */ - @JsonCreator - public static SelectByType fromString(String name) throws IllegalArgumentException { - return SelectByType.valueOf(name.toUpperCase()); - } - - @Override - public String toString() { - return name().toLowerCase(); - } - - } - - /** - * The type that an option is selected by. - */ - @NotNull - private SelectByType selectBy; - - @Override - public ExecuteResult execute(WebSiteConnector connector) { - final WebElementLocator nodeWithVariables = - new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - - try { - final String valueWithVariables = insertVariableValues(value); - - final WebElement selectElement = connector.getElement(nodeWithVariables); - final Select select = new Select(selectElement); - switch (selectBy) { - case VALUE: - select.selectByValue(valueWithVariables); - break; - case TEXT: - select.selectByVisibleText(valueWithVariables); - break; - case INDEX: - select.selectByIndex(Integer.parseInt(value)); - break; - default: - select.selectByIndex(0); - break; - } - - logger.info(LoggerMarkers.LEARNER, "Selected '{}' of '{}' by '{}'.", - value, nodeWithVariables, selectBy); - return getSuccessOutput(); - } catch (NoSuchElementException | NumberFormatException | UnexpectedTagNameException e) { - logger.info(LoggerMarkers.LEARNER, "Could not select '{}' of '{}' by '{}'.", - value, nodeWithVariables, selectBy, e); - return getFailedOutput(); - } - } - - public SelectByType getSelectBy() { - return selectBy; - } - - public void setSelectBy(SelectByType selectBy) { - this.selectBy = selectBy; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/SubmitAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/SubmitAction.java deleted file mode 100644 index e3a1bbf9e..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/SubmitAction.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.NoSuchElementException; - -/** - * Action to submit a specific element. - */ -@Entity -@DiscriminatorValue("web_submit") -@JsonTypeName("web_submit") -public class SubmitAction extends WebSymbolAction { - - /** The information to identify the element. */ - @NotNull - @Embedded - private WebElementLocator node; - - @Override - public ExecuteResult execute(WebSiteConnector connector) { - final WebElementLocator nodeWithVariables = - new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - - try { - connector.getElement(nodeWithVariables).submit(); - - logger.info(LoggerMarkers.LEARNER, "Submitted '{}'.", nodeWithVariables); - return getSuccessOutput(); - } catch (NoSuchElementException e) { - logger.info(LoggerMarkers.LEARNER, "Could not submit '{}'.", nodeWithVariables, e); - return getFailedOutput(); - } - } - - public WebElementLocator getNode() { - return node; - } - - public void setNode(WebElementLocator node) { - this.node = node; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/SwitchToAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/SwitchToAction.java deleted file mode 100644 index 83844d695..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/SwitchToAction.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.WebDriver; - -/** - * Action to submit a specific element. - */ -@Entity -@DiscriminatorValue("web_switchTo") -@JsonTypeName("web_switchTo") -public class SwitchToAction extends WebSymbolAction { - - /** - * The target to switch to. - */ - private enum TargetType { - - /** The parent frame. */ - PARENT_FRAME, - - /** The default browser frame. */ - DEFAULT_CONTENT, - - /** The last frame that has been visited. */ - LAST_FRAME, - - /** A new window that has been opened. */ - WINDOW, - - /** The default window. */ - DEFAULT_WINDOW, - } - - /** - * The target type. - */ - @NotNull - private TargetType target; - - @Override - protected ExecuteResult execute(WebSiteConnector connector) { - try { - final WebDriver wd = connector.getDriver(); - switch (target) { - case PARENT_FRAME: - wd.switchTo().parentFrame(); - break; - case DEFAULT_CONTENT: - wd.switchTo().defaultContent(); - break; - case LAST_FRAME: - wd.switchTo().frame(connector.getLastFrame()); - break; - case WINDOW: - for (final String handle : wd.getWindowHandles()) { - wd.switchTo().window(handle); - } - break; - case DEFAULT_WINDOW: - final String mainHandle = wd.getWindowHandles().iterator().next(); - wd.switchTo().window(mainHandle); - break; - default: - throw new Exception("Undefined target type."); - } - logger.info(LoggerMarkers.LEARNER, "Switch to '{}'", target); - return getSuccessOutput(); - } catch (Exception e) { - logger.info(LoggerMarkers.LEARNER, "Could not switch to '{}'", target, e); - return getFailedOutput(); - } - } - - public TargetType getTarget() { - return target; - } - - public void setTarget(TargetType target) { - this.target = target; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/SwitchToFrameAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/SwitchToFrameAction.java deleted file mode 100644 index 895766504..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/SwitchToFrameAction.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.WebElement; - -/** - * Action to submit a specific element. - */ -@Entity -@DiscriminatorValue("web_switchToFrame") -@JsonTypeName("web_switchToFrame") -public class SwitchToFrameAction extends WebSymbolAction { - - /** - * The element to switch to. - */ - @NotNull - @Embedded - private WebElementLocator node; - - @Override - protected ExecuteResult execute(WebSiteConnector connector) { - final WebElementLocator nodeWithVariables = - new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - - try { - final WebElement element = connector.getElement(nodeWithVariables); - connector.getDriver().switchTo().frame(element); - connector.setLastFrame(element); - logger.info(LoggerMarkers.LEARNER, "Switch to frame with selector '{}'", nodeWithVariables); - return getSuccessOutput(); - } catch (Exception e) { - logger.info(LoggerMarkers.LEARNER, "Could not switch to frame with selector '{}'", nodeWithVariables); - return getFailedOutput(); - } - } - - public WebElementLocator getNode() { - return node; - } - - public void setNode(WebElementLocator node) { - this.node = node; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/UploadFileAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/UploadFileAction.java deleted file mode 100644 index 56863d9e8..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/UploadFileAction.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.FileStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; - -/** Action to upload a file into an input[type="file"] element. */ -@Entity -@DiscriminatorValue("web_uploadFile") -@JsonTypeName("web_uploadFile") -public class UploadFileAction extends SymbolAction { - - /** The input element to upload the file to. */ - @NotNull - @Embedded - private WebElementLocator node; - - /** The name of the uploaded file in ALEX. */ - @NotEmpty - private String fileName; - - @Override - protected ExecuteResult execute(ConnectorManager connector) { - final FileStoreConnector fileStore = connector.getConnector(FileStoreConnector.class); - final WebSiteConnector webSiteConnector = connector.getConnector(WebSiteConnector.class); - - final WebElementLocator nodeWithVariables = - new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - - try { - final String path = fileStore.getAbsoluteFileLocation(symbol.getProjectId(), fileName); - final WebElement el = webSiteConnector.getElement(nodeWithVariables); - - if (el.getTagName().equals("input") && el.getAttribute("type").equals("file")) { - el.sendKeys(path); - return getSuccessOutput(); - } else { - throw new NoSuchElementException("The element is not an input file element."); - } - } catch (IllegalStateException e) { - logger.info(LoggerMarkers.LEARNER, "The file '{}' could not be found in ALEX.", this.fileName); - return getFailedOutput(); - } catch (NoSuchElementException e) { - logger.info(LoggerMarkers.LEARNER, "The element could not be found or is not an input element."); - return getFailedOutput(); - } catch (Exception e) { - logger.info(LoggerMarkers.LEARNER, "The file could not be uploaded for an unknown reason", e); - return getFailedOutput(); - } - } - - public WebElementLocator getNode() { - return node; - } - - public void setNode(WebElementLocator node) { - this.node = node; - } - - public String getFileName() { - return fileName; - } - - public void setFileName(String fileName) { - this.fileName = fileName; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/WaitForNodeAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/WaitForNodeAction.java deleted file mode 100644 index 3a0b3156f..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/WaitForNodeAction.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.TimeoutException; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.ui.WebDriverWait; - -import java.time.Duration; - -/** - * Action to wait for the state of an element to change. - */ -@Entity -@DiscriminatorValue("web_waitForNode") -@JsonTypeName("web_waitForNode") -public class WaitForNodeAction extends WebSymbolAction { - - /** - * Enumeration to specify the wait criterion. - */ - public enum WaitCriterion { - - /** - * If an element is attached to the DOM and visible. - */ - VISIBLE, - - /** - * If an element is attached to the DOM but not visible. - */ - INVISIBLE, - - /** - * If an element is added to the DOM tree. - */ - ADDED, - - /** - * If an element is removed from the DOM tree. - */ - REMOVED, - - /** - * If an element is clickable. - */ - CLICKABLE; - - /** - * Parser function to handle the enum names case insensitive. - * - * @param name - * The enum name. - * @return The corresponding WaitCriterion. - * @throws IllegalArgumentException - * If the name could not be parsed. - */ - @JsonCreator - public static WaitCriterion fromString(String name) throws IllegalArgumentException { - return WaitCriterion.valueOf(name.toUpperCase()); - } - - @Override - public String toString() { - return name().toLowerCase(); - } - } - - /** - * The css selector of the element. - */ - @NotNull - @Embedded - private WebElementLocator node; - - /** - * Which criterion is used to wait for the title. - */ - @NotNull - private WaitCriterion waitCriterion; - - /** - * How many seconds should be waited before the action fails. - */ - @NotNull - @Min(0) - private long maxWaitTime; - - @Override - protected ExecuteResult execute(WebSiteConnector connector) { - if (maxWaitTime < 0) { - return getFailedOutput(); - } - - final WebDriverWait wait = new WebDriverWait(connector.getDriver(), Duration.ofSeconds(maxWaitTime)); - final WebElementLocator nodeWithVariables = new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - - try { - logger.info(LoggerMarkers.LEARNER, "Wait for element '{}' (criterion: '{}').", - nodeWithVariables, waitCriterion); - switch (waitCriterion) { - case VISIBLE: - wait.until(wd -> { - try { - return connector.getElement(nodeWithVariables).isDisplayed(); - } catch (Exception e) { - return false; - } - }); - break; - case INVISIBLE: - wait.until(wd -> { - try { - return !connector.getElement(nodeWithVariables).isDisplayed(); - } catch (Exception e) { - return false; - } - }); - break; - case ADDED: - wait.until(wd -> { - try { - connector.getElement(nodeWithVariables); - return true; - } catch (Exception e) { - return false; - } - }); - break; - case REMOVED: - wait.until(wd -> { - try { - connector.getElement(nodeWithVariables); - return false; - } catch (Exception e) { - return true; - } - }); - break; - case CLICKABLE: - wait.until(wd -> { - try { - final WebElement element = connector.getElement(nodeWithVariables); - return element.isDisplayed() && element.isEnabled(); - } catch (Exception e) { - return false; - } - }); - break; - default: - return getFailedOutput(); - } - return getSuccessOutput(); - } catch (TimeoutException e) { - logger.info(LoggerMarkers.LEARNER, "Waiting on the node '{}' (criterion: '{}') timed out.", - nodeWithVariables, waitCriterion); - return getFailedOutput(); - } catch (NoSuchElementException e) { - logger.info(LoggerMarkers.LEARNER, "The node with the selector {} (criterion: '{}') could not be found.", - nodeWithVariables, waitCriterion); - return getFailedOutput(); - } - } - - public WebElementLocator getNode() { - return node; - } - - public void setNode(WebElementLocator node) { - this.node = node; - } - - public WaitCriterion getWaitCriterion() { - return waitCriterion; - } - - public void setWaitCriterion(WaitCriterion waitCriterion) { - this.waitCriterion = waitCriterion; - } - - public long getMaxWaitTime() { - return maxWaitTime; - } - - public void setMaxWaitTime(long maxWaitTime) { - this.maxWaitTime = maxWaitTime; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/WaitForNodeAttributeAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/WaitForNodeAttributeAction.java deleted file mode 100644 index e751fa4a5..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/WaitForNodeAttributeAction.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.TimeoutException; -import org.openqa.selenium.support.ui.WebDriverWait; - -import java.time.Duration; - -/** - * Action to wait for a node attribute value. - */ -@Entity -@DiscriminatorValue("web_waitForNodeAttribute") -@JsonTypeName("web_waitForNodeAttribute") -public class WaitForNodeAttributeAction extends WebSymbolAction { - - /** Enum to specify the wait criterion. */ - public enum WaitCriterion { - - /** If the title should be the value. */ - IS, - - /** If the title should contain the value. */ - CONTAINS - } - - /** The value the attribute should match / contain. */ - @NotBlank - @Column(name = "\"value\"") - private String value; - - /** The attribute to wait for. */ - @NotBlank - private String attribute; - - /** Which criterion is used to wait for the title. */ - @NotNull - private WaitCriterion waitCriterion; - - /** How many seconds should be waited before the action fails. */ - @NotNull - @Min(0) - private long maxWaitTime; - - /** The element. */ - @NotNull - @Embedded - private WebElementLocator node; - - @Override - protected ExecuteResult execute(WebSiteConnector connector) { - if (maxWaitTime < 0) { - return getFailedOutput(); - } - - final WebDriverWait wait = new WebDriverWait(connector.getDriver(), Duration.ofSeconds(maxWaitTime)); - final WebElementLocator nodeWithVariables = - new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - - final String valueWithVariables = insertVariableValues(value); - - try { - switch (waitCriterion) { - case IS: - wait.until(wd -> connector.getElement(nodeWithVariables) - .getAttribute(attribute) - .equals(valueWithVariables)); - break; - case CONTAINS: - wait.until(wd -> connector.getElement(nodeWithVariables) - .getAttribute(attribute) - .contains(valueWithVariables)); - break; - default: - return getFailedOutput(); - } - - return getSuccessOutput(); - } catch (TimeoutException e) { - logger.info(LoggerMarkers.LEARNER, "Waiting on the attribute '{}' (criterion: '{}') timed out. ", - attribute, waitCriterion); - return getFailedOutput(); - } - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - public String getAttribute() { - return attribute; - } - - public void setAttribute(String attribute) { - this.attribute = attribute; - } - - public WaitCriterion getWaitCriterion() { - return waitCriterion; - } - - public void setWaitCriterion(WaitCriterion waitCriterion) { - this.waitCriterion = waitCriterion; - } - - public long getMaxWaitTime() { - return maxWaitTime; - } - - public void setMaxWaitTime(long maxWaitTime) { - this.maxWaitTime = maxWaitTime; - } - - public WebElementLocator getNode() { - return node; - } - - public void setNode(WebElementLocator node) { - this.node = node; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/WaitForScriptAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/WaitForScriptAction.java deleted file mode 100644 index 92d4d1281..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/WaitForScriptAction.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.data.utils.ExecuteScriptUtils; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; - -import java.time.Duration; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.JavascriptExecutor; -import org.openqa.selenium.support.ui.WebDriverWait; - -@Entity -@DiscriminatorValue("web_waitForScript") -@JsonTypeName("web_waitForScript") -public class WaitForScriptAction extends SymbolAction { - - private static final int DEFAULT_SCRIPT_TIMEOUT = 10; - - @NotBlank - @Column(columnDefinition = "TEXT") - private String script; - - /** When the script should be timed out in s. */ - @NotNull - @Min(value = 0) - private int timeout = DEFAULT_SCRIPT_TIMEOUT; - - /** The time to wait before a timeout. */ - @NotNull - @Min(0) - private long maxWaitTime; - - @Override - protected ExecuteResult execute(ConnectorManager connector) { - final WebSiteConnector webSiteConnector = connector.getConnector(WebSiteConnector.class); - - if (webSiteConnector.getDriver() instanceof JavascriptExecutor) { - final WebDriverWait wait = new WebDriverWait(webSiteConnector.getDriver(), Duration.ofSeconds(maxWaitTime)); - - try { - webSiteConnector.getDriver().manage().timeouts().setScriptTimeout(timeout, TimeUnit.SECONDS); - - final Map> store = ExecuteScriptUtils.createScriptStore(connector); - final Object returnValue = ((JavascriptExecutor) webSiteConnector.getDriver()).executeScript(script, store); - if (!(returnValue instanceof Boolean)) { - logger.info(LoggerMarkers.LEARNER, "Script does not return boolean result."); - return getFailedOutput(); - } - - wait.until(wd -> { - final Object val = ((JavascriptExecutor) webSiteConnector.getDriver()).executeScript(script, store); - return (boolean) val; - }); - - logger.info(LoggerMarkers.LEARNER, "Waiting for JavaScript success"); - return getSuccessOutput(); - } catch (Exception e) { - logger.info(LoggerMarkers.LEARNER, "Could not execute JavaScript", e); - return getFailedOutput(); - } - } else { - logger.info(LoggerMarkers.LEARNER, "This driver does not support JavaScript!"); - return getFailedOutput(); - } - } - - public String getScript() { - return script; - } - - public void setScript(String script) { - this.script = script; - } - - public int getTimeout() { - return timeout; - } - - public void setTimeout(int timeout) { - this.timeout = timeout; - } - - public long getMaxWaitTime() { - return maxWaitTime; - } - - public void setMaxWaitTime(long maxWaitTime) { - this.maxWaitTime = maxWaitTime; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/WaitForTextAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/WaitForTextAction.java deleted file mode 100644 index 156648cfc..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/WaitForTextAction.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; - -import java.time.Duration; -import java.util.regex.Pattern; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.TimeoutException; -import org.openqa.selenium.support.ui.WebDriverWait; - -/** - * Action to wait for a text to be present on the page. - */ -@Entity -@DiscriminatorValue("web_waitForText") -@JsonTypeName("web_waitForText") -public class WaitForTextAction extends WebSymbolAction { - - /** - * The string or pattern to look for. - */ - @NotBlank - @Column(name = "\"value\"", columnDefinition = "TEXT") - private String value; - - /** - * If the text is interpreted as a regular expression. - */ - @NotNull - @Column(name = "\"regexp\"") - private boolean regexp; - - /** - * The element to look for the text. The whole document is used by default. - */ - @NotNull - private WebElementLocator node; - - /** - * The time to wait before a timeout. - */ - @NotNull - @Min(0) - private long maxWaitTime; - - /** - * Constructor. - */ - public WaitForTextAction() { - this.regexp = false; - this.node = new WebElementLocator(); - this.node.setSelector("body"); - this.node.setType(WebElementLocator.Type.CSS); - this.maxWaitTime = 1; - } - - @Override - protected ExecuteResult execute(final WebSiteConnector connector) { - final WebDriverWait wait = new WebDriverWait(connector.getDriver(), Duration.ofSeconds(maxWaitTime)); - - final WebElementLocator nodeWithVariables = - new WebElementLocator(insertVariableValues(node.getSelector()), node.getType()); - final String valueWithVariables = insertVariableValues(value); - - try { - if (regexp) { - logger.info(LoggerMarkers.LEARNER, "Waiting for pattern '{}' to be present in node '{}' for a maximum of " - + "{}ms.", valueWithVariables, nodeWithVariables, maxWaitTime); - wait.until(wd -> { - final String text = connector.getElement(nodeWithVariables).getText(); - return Pattern.compile(value).matcher(text).find(); - }); - } else { - logger.info(LoggerMarkers.LEARNER, "Waiting for text '{}' to be present in node '{}' for a maximum of {}ms.", - valueWithVariables, nodeWithVariables, maxWaitTime); - wait.until(wd -> connector.getElement(nodeWithVariables).getText().contains(valueWithVariables)); - } - - return getSuccessOutput(); - } catch (NoSuchElementException | TimeoutException e) { - logger.info(LoggerMarkers.LEARNER, "Waiting for text/patter '{}' to be present in node '{}' failed.", - valueWithVariables, nodeWithVariables); - return getFailedOutput(); - } - } - - public String getValue() { - return value; - } - - public void setValue(String text) { - this.value = text; - } - - public boolean isRegexp() { - return regexp; - } - - public void setRegexp(boolean regex) { - this.regexp = regex; - } - - public WebElementLocator getNode() { - return node; - } - - public void setNode(WebElementLocator node) { - this.node = node; - } - - public long getMaxWaitTime() { - return maxWaitTime; - } - - public void setMaxWaitTime(long maxWaitTime) { - this.maxWaitTime = maxWaitTime; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/WaitForTitleAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/WaitForTitleAction.java deleted file mode 100644 index e59d9efb6..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/WaitForTitleAction.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import org.openqa.selenium.TimeoutException; -import org.openqa.selenium.support.ui.WebDriverWait; - -import java.time.Duration; - -/** - * Action to wait for the title of a page to change. - */ -@Entity -@DiscriminatorValue("web_waitForTitle") -@JsonTypeName("web_waitForTitle") -public class WaitForTitleAction extends WebSymbolAction { - - /** - * Enumeration to specify the wait criterion. - */ - public enum WaitCriterion { - - /** - * If the title should be the value. - */ - IS, - - /** - * If the title should contain the value. - */ - CONTAINS; - - /** - * Parser function to handle the enum names case insensitive. - * - * @param name - * The enum name. - * @return The corresponding WaitCriterion. - * @throws IllegalArgumentException - * If the name could not be parsed. - */ - @JsonCreator - public static WaitCriterion fromString(String name) throws IllegalArgumentException { - return WaitCriterion.valueOf(name.toUpperCase()); - } - - @Override - public String toString() { - return name().toLowerCase(); - } - } - - /** - * The value the title should match / contain. - */ - @NotBlank - @Column(name = "\"value\"") - private String value; - - /** - * Which criterion is used to wait for the title. - */ - @NotNull - private WaitCriterion waitCriterion; - - /** - * How many seconds should be waited before the action fails. - */ - @NotNull - @Min(0) - private long maxWaitTime; - - @Override - protected ExecuteResult execute(WebSiteConnector connector) { - if (maxWaitTime < 0) { - return getFailedOutput(); - } - - final WebDriverWait wait = new WebDriverWait(connector.getDriver(), Duration.ofSeconds(maxWaitTime)); - final String valueWithVariables = insertVariableValues(value); - - try { - switch (waitCriterion) { - case IS: - wait.until(wd -> wd.getTitle().equals(valueWithVariables)); - break; - case CONTAINS: - wait.until(wd -> wd.getTitle().contains(valueWithVariables)); - break; - default: - return getFailedOutput(); - } - - return getSuccessOutput(); - } catch (TimeoutException e) { - logger.info(LoggerMarkers.LEARNER, "Waiting on the title '{}' (criterion: '{}') timed out. " - + "Last known title was '{}'.", - valueWithVariables, waitCriterion, connector.getDriver().getTitle()); - return getFailedOutput(); - } - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - public WaitCriterion getWaitCriterion() { - return waitCriterion; - } - - public void setWaitCriterion(WaitCriterion waitCriterion) { - this.waitCriterion = waitCriterion; - } - - public long getMaxWaitTime() { - return maxWaitTime; - } - - public void setMaxWaitTime(long maxWaitTime) { - this.maxWaitTime = maxWaitTime; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/WebSymbolAction.java b/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/WebSymbolAction.java deleted file mode 100644 index 59cba9f5f..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/actions/web/WebSymbolAction.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; - -/** - * Base for the different action a test could do. This action layer is basically a wrapper around Selenium to be more OO - * and can be (de-)serialized in JSON. - */ -@Entity -@DiscriminatorValue("web") -@JsonTypeName("web") -public abstract class WebSymbolAction extends SymbolAction { - - @Override - public ExecuteResult execute(ConnectorManager connector) { - return execute(connector.getConnector(WebSiteConnector.class)); - } - - /** - * Execute a Web action, i.e. an action that interacts with a web site over an browser. - * - * @param connector - * The connector to connect to web site (via Selenium). - * @return An indicator of the action was executed successfully or not. - */ - protected abstract ExecuteResult execute(WebSiteConnector connector); - - @Override - public String toString() { - return "WebSymbolsAction[" + id + "] " + getClass().getName(); - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/export/ExportableEntity.java b/backend/src/main/java/de/learnlib/alex/data/entities/export/ExportableEntity.java deleted file mode 100644 index 5322c334c..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/export/ExportableEntity.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.export; - -public abstract class ExportableEntity { - - /** The version of ALEX. */ - private String version; - - /** The identifier for what is exported. */ - private String type; - - public ExportableEntity(String version, String type) { - this.version = version; - this.type = type; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/export/ProjectExportableEntity.java b/backend/src/main/java/de/learnlib/alex/data/entities/export/ProjectExportableEntity.java deleted file mode 100644 index 207ccdb8c..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/export/ProjectExportableEntity.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.export; - -import com.fasterxml.jackson.databind.JsonNode; - -public class ProjectExportableEntity extends ExportableEntity { - - private JsonNode project; - - private JsonNode groups; - - private JsonNode tests; - - private JsonNode formulaSuites; - - private JsonNode learnerSetups; - - private JsonNode testExecutionConfigs; - - public ProjectExportableEntity() { - super("-1", "project"); - } - - public ProjectExportableEntity(String version, JsonNode project) { - super(version, "project"); - this.project = project; - } - - public JsonNode getProject() { - return project; - } - - public void setProject(JsonNode project) { - this.project = project; - } - - public JsonNode getGroups() { - return groups; - } - - public void setGroups(JsonNode groups) { - this.groups = groups; - } - - public JsonNode getTests() { - return tests; - } - - public void setTests(JsonNode tests) { - this.tests = tests; - } - - public JsonNode getFormulaSuites() { - return formulaSuites; - } - - public void setFormulaSuites(JsonNode formulaSuites) { - this.formulaSuites = formulaSuites; - } - - public JsonNode getLearnerSetups() { - return learnerSetups; - } - - public void setLearnerSetups(JsonNode learnerSetups) { - this.learnerSetups = learnerSetups; - } - - public JsonNode getTestExecutionConfigs() { - return testExecutionConfigs; - } - - public void setTestExecutionConfigs(JsonNode testExecutionConfigs) { - this.testExecutionConfigs = testExecutionConfigs; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/export/SymbolGroupsExportableEntity.java b/backend/src/main/java/de/learnlib/alex/data/entities/export/SymbolGroupsExportableEntity.java deleted file mode 100644 index 6071700df..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/export/SymbolGroupsExportableEntity.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.export; - -import com.fasterxml.jackson.databind.JsonNode; - -public class SymbolGroupsExportableEntity extends ExportableEntity { - - private JsonNode symbolGroups; - - public SymbolGroupsExportableEntity(String version, JsonNode symbolGroups) { - super(version, "symbolGroups"); - this.symbolGroups = symbolGroups; - } - - public JsonNode getSymbolGroups() { - return symbolGroups; - } - - public void setSymbolGroups(JsonNode symbolGroups) { - this.symbolGroups = symbolGroups; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/export/SymbolsExportConfig.java b/backend/src/main/java/de/learnlib/alex/data/entities/export/SymbolsExportConfig.java deleted file mode 100644 index 797b460ca..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/export/SymbolsExportConfig.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.export; - -import java.util.ArrayList; -import java.util.List; - -public class SymbolsExportConfig { - - /** The ids of the symbols to export. */ - private List symbolIds = new ArrayList<>(); - - /** If true, symbols are exported in a flat array without their groups. */ - private boolean symbolsOnly; - - public boolean isSymbolsOnly() { - return symbolsOnly; - } - - public void setSymbolsOnly(boolean symbolsOnly) { - this.symbolsOnly = symbolsOnly; - } - - public List getSymbolIds() { - return symbolIds; - } - - public void setSymbolIds(List symbolIds) { - this.symbolIds = symbolIds; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/entities/export/SymbolsExportableEntity.java b/backend/src/main/java/de/learnlib/alex/data/entities/export/SymbolsExportableEntity.java deleted file mode 100644 index 37bf986ea..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/entities/export/SymbolsExportableEntity.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.export; - -import com.fasterxml.jackson.databind.JsonNode; - -public class SymbolsExportableEntity extends ExportableEntity { - - private JsonNode symbols; - - public SymbolsExportableEntity(String version, JsonNode symbols) { - super(version, "symbols"); - this.symbols = symbols; - } - - public JsonNode getSymbols() { - return symbols; - } - - public void setSymbols(JsonNode symbols) { - this.symbols = symbols; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/events/ProjectEvent.java b/backend/src/main/java/de/learnlib/alex/data/events/ProjectEvent.java deleted file mode 100644 index 5f953ea54..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/events/ProjectEvent.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.events; - -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.webhooks.entities.Event; -import de.learnlib.alex.webhooks.entities.EventType; - -/** Project events. */ -public class ProjectEvent { - - /** Event for when a project is created. */ - public static class Created extends Event { - - /** - * Constructor. - * - * @param project - * The created project. - */ - public Created(Project project) { - super(project, EventType.PROJECT_CREATED); - } - } - - /** Event for when a project is deleted. */ - public static class Deleted extends Event { - - /** - * Constructor. - * - * @param id - * The id of the deleted project. - */ - public Deleted(Long id) { - super(id, EventType.PROJECT_DELETED); - } - } - - /** Event for when a project is updated. */ - public static class Updated extends Event { - - /** - * Constructor. - * - * @param project - * The updated project. - */ - public Updated(Project project) { - super(project, EventType.PROJECT_UPDATED); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/events/SymbolEvent.java b/backend/src/main/java/de/learnlib/alex/data/events/SymbolEvent.java deleted file mode 100644 index 82488bce2..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/events/SymbolEvent.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.events; - -import static de.learnlib.alex.webhooks.entities.EventType.SYMBOLS_CREATED; -import static de.learnlib.alex.webhooks.entities.EventType.SYMBOLS_DELETED; -import static de.learnlib.alex.webhooks.entities.EventType.SYMBOLS_UPDATED; -import static de.learnlib.alex.webhooks.entities.EventType.SYMBOL_CREATED; -import static de.learnlib.alex.webhooks.entities.EventType.SYMBOL_DELETED; -import static de.learnlib.alex.webhooks.entities.EventType.SYMBOL_UPDATED; - -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.webhooks.entities.Event; -import java.util.List; - -/** Symbol related events. */ -public class SymbolEvent { - - /** Event for when a symbol is created. */ - public static class Created extends Event { - - /** - * Constructor. - * - * @param symbol - * The created symbol. - */ - public Created(Symbol symbol) { - super(symbol, SYMBOL_CREATED); - } - } - - /** Event for when multiple symbols are created at once. */ - public static class CreatedMany extends Event> { - - /** - * Constructor. - * - * @param symbols - * The created symbols. - */ - public CreatedMany(List symbols) { - super(symbols, SYMBOLS_CREATED); - } - } - - /** Event for when a symbol is updated. */ - public static class Updated extends Event { - - /** - * Constructor. - * - * @param symbol - * The updated symbol. - */ - public Updated(Symbol symbol) { - super(symbol, SYMBOL_UPDATED); - } - } - - /** Event for when multiple symbols are updated at once. */ - public static class UpdatedMany extends Event> { - - /** - * Constructor. - * - * @param symbols - * The updated symbols. - */ - public UpdatedMany(List symbols) { - super(symbols, SYMBOLS_UPDATED); - } - } - - public static class Deleted extends Event { - public Deleted(Long id) { - super(id, SYMBOL_DELETED); - } - } - - public static class DeletedMany extends Event> { - public DeletedMany(List ids) { - super(ids, SYMBOLS_DELETED); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/events/SymbolGroupEvent.java b/backend/src/main/java/de/learnlib/alex/data/events/SymbolGroupEvent.java deleted file mode 100644 index 912056dec..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/events/SymbolGroupEvent.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.events; - -import de.learnlib.alex.data.entities.SymbolGroup; -import de.learnlib.alex.webhooks.entities.Event; -import de.learnlib.alex.webhooks.entities.EventType; -import java.util.List; - -/** Symbol group events. */ -public class SymbolGroupEvent { - - /** Event for when a symbol group is created. */ - public static class Created extends Event { - - /** - * Constructor. - * - * @param symbolGroup - * The created symbol group . - */ - public Created(SymbolGroup symbolGroup) { - super(symbolGroup, EventType.SYMBOL_GROUP_CREATED); - } - } - - /** Event for when a symbol group is created. */ - public static class CreatedMany extends Event> { - - /** - * Constructor. - * - * @param symbolGroups - * The created symbol group . - */ - public CreatedMany(List symbolGroups) { - super(symbolGroups, EventType.SYMBOL_GROUPS_CREATED); - } - } - - /** Event for when a symbol group is deleted. */ - public static class Deleted extends Event { - - /** - * Constructor. - * - * @param id - * The id of the deleted symbol group . - */ - public Deleted(Long id) { - super(id, EventType.SYMBOL_GROUP_DELETED); - } - } - - /** Event for when a symbol group is updated. */ - public static class Updated extends Event { - - /** - * Constructor. - * - * @param symbolGroup - * The updated symbol group . - */ - public Updated(SymbolGroup symbolGroup) { - super(symbolGroup, EventType.SYMBOL_GROUP_UPDATED); - } - } - - /** Event for when a symbol group is moved. */ - public static class Moved extends Event { - - /** - * Constructor. - * - * @param symbolGroup - * The moved symbol group . - */ - public Moved(SymbolGroup symbolGroup) { - super(symbolGroup, EventType.SYMBOL_GROUP_MOVED); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/repositories/CounterRepository.java b/backend/src/main/java/de/learnlib/alex/data/repositories/CounterRepository.java deleted file mode 100644 index 0ec20df29..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/repositories/CounterRepository.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.repositories; - -import de.learnlib.alex.data.entities.Counter; -import de.learnlib.alex.data.entities.Project; -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** - * Repository to persist Counters. - */ -@Repository -public interface CounterRepository extends JpaRepository { - - /** - * Find all counters in a Project of an User. - * - * @param project - * The ID the Project the Counter belongs to. - * @return The Counters in the Project. - */ - List findAllByProject(Project project); - - /** - * Get counters by their IDs. - * - * @param ids - * The IDs of the counters. - * @return The counters. - */ - List findAllByIdIn(List ids); - - /** - * Find a Counter by its name. - * - * @param project - * The ID the Project the Counters belongs to. - * @param name - * The names of the Counter. - * @return The Counter or null. - */ - Counter findByProjectAndName(Project project, String name); - - Counter findByProject_IdAndName(Long projectId, String name); -} diff --git a/backend/src/main/java/de/learnlib/alex/data/repositories/ParameterizedSymbolRepository.java b/backend/src/main/java/de/learnlib/alex/data/repositories/ParameterizedSymbolRepository.java deleted file mode 100644 index 412605822..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/repositories/ParameterizedSymbolRepository.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.repositories; - -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** - * The JPA repository for parameterized symbols {@link ParameterizedSymbol}. - */ -@Repository -public interface ParameterizedSymbolRepository extends JpaRepository { - - /** - * Get all parameterized symbols by symbol ID. - * - * @param symbolId - * The ID of the symbol. - * @return The parameterized symbols. - */ - List findAllBySymbol_Id(Long symbolId); - - /** - * Count all by symbol ID. - * - * @param symbolId - * The ID of the symbol. - * @return The count. - */ - Long countAllBySymbol_Id(Long symbolId); - - /** - * Delete all parameterized symbols by project ID. - * - * @param projectId - * The ID of the project. - * @return The number of deleted parameterized symbols. - */ - Long deleteAllBySymbol_Project_Id(Long projectId); -} diff --git a/backend/src/main/java/de/learnlib/alex/data/repositories/ProjectEnvironmentRepository.java b/backend/src/main/java/de/learnlib/alex/data/repositories/ProjectEnvironmentRepository.java deleted file mode 100644 index 49dd66aea..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/repositories/ProjectEnvironmentRepository.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.repositories; - -import de.learnlib.alex.data.entities.ProjectEnvironment; -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.stereotype.Repository; - -@Repository -public interface ProjectEnvironmentRepository extends JpaRepository { - - List findAllByProject_Id(Long projectId); - - ProjectEnvironment findByProject_IdAndNameAndIdNot(Long projectId, String name, Long envId); - - ProjectEnvironment findByProject_IdAndName(Long projectId, String name); - - @Query(nativeQuery = true, value = "select * from PUBLIC.project_environment where project_id = ? and is_default = ? limit 1") - ProjectEnvironment findByProject_IdAndIs_Default(Long projectId, Boolean isDefault); - - List findAllByIdIn(List ids); - - List findByProject_IdAndNameIn(Long projectId, List names); - - ProjectEnvironment findByProject_IdAndId(Long projectId, Long environmentId); -} diff --git a/backend/src/main/java/de/learnlib/alex/data/repositories/ProjectEnvironmentVariableRepository.java b/backend/src/main/java/de/learnlib/alex/data/repositories/ProjectEnvironmentVariableRepository.java deleted file mode 100644 index d3eeb5e1b..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/repositories/ProjectEnvironmentVariableRepository.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.repositories; - -import de.learnlib.alex.data.entities.ProjectEnvironmentVariable; -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface ProjectEnvironmentVariableRepository extends JpaRepository { - - ProjectEnvironmentVariable findByEnvironment_IdAndName(Long envId, String name); - - ProjectEnvironmentVariable findByEnvironment_IdAndNameAndIdNot(Long envId, String name, Long varId); - - void deleteAllByEnvironment_Project_IdAndName(Long projectId, String name); - - List findAllByEnvironment_Project_IdAndName(Long projectId, String name); -} diff --git a/backend/src/main/java/de/learnlib/alex/data/repositories/ProjectRepository.java b/backend/src/main/java/de/learnlib/alex/data/repositories/ProjectRepository.java deleted file mode 100644 index 781140d1f..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/repositories/ProjectRepository.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.repositories; - -import de.learnlib.alex.data.entities.Project; -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; - -/** - * Repository to persist Projects. - */ -@Repository -public interface ProjectRepository extends JpaRepository { - - /** - * Find all projects of an User. - * - * @param userId - * The ID the User the Projects belongs to. - * @return The Projects of the User. - */ - @Query(value = "select p from Project p where " - + " p in (select p from Project p Join p.owners o where o.id = :id)" - + " or p in (select p from Project p Join p.members m where m.id = :id)") - List findAllByUser_Id(@Param("id") Long userId); - - @Query(value = "select p from Project p where " - + " p in (select p from Project p Join p.owners o where o.id = :id and p.name = :name and p.id <> :projectId)" - + " or p in (select p from Project p Join p.members m where m.id = :id and p.name = :name and p.id <> :projectId)") - Project findByUser_IdAndNameAndIdNot(@Param("id") Long userId, @Param("name") String name, @Param("projectId") Long projectId); -} diff --git a/backend/src/main/java/de/learnlib/alex/data/repositories/ProjectUrlRepository.java b/backend/src/main/java/de/learnlib/alex/data/repositories/ProjectUrlRepository.java deleted file mode 100644 index 2a44a851d..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/repositories/ProjectUrlRepository.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.repositories; - -import de.learnlib.alex.data.entities.ProjectUrl; -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** The repository for project URLs. */ -@Repository -public interface ProjectUrlRepository extends JpaRepository { - - void deleteByEnvironment_IdAndName(Long environmentId, String name); - - ProjectUrl findByEnvironment_IdAndNameAndIdNot(Long environmentId, String name, Long urlId); - - ProjectUrl findByEnvironment_IdAndName(Long environmentId, String name); - - List findByEnvironment_Project_IdAndIsDefault(Long projectId, boolean isDefault); - - List findByEnvironment_Project_IdAndName(Long projectId, String name); -} diff --git a/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolActionRepository.java b/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolActionRepository.java deleted file mode 100644 index 3c4ff4702..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolActionRepository.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.repositories; - -import de.learnlib.alex.data.entities.SymbolAction; -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.stereotype.Repository; - -/** - * The repository for symbol actions. - */ -@Repository -public interface SymbolActionRepository extends JpaRepository { - - /** - * Delete all actions by a symbol ID. - * - * @param symbolId - * The ID of the symbol. - */ - void deleteAllBySymbol_Id(Long symbolId); - - /** - * Delete all actions by a project ID. - * - * @param projectId - * The ID of the project. - */ - void deleteAllBySymbol_Project_Id(Long projectId); - - @Query("SELECT a FROM SymbolAction a WHERE a.symbol.project.id = ?1 AND BASE_URL = ?2 AND (TYPE = 'web_goto' OR TYPE = 'rest_call')") - List findAllWithBaseUrl(Long projectId, String baseUrl); -} diff --git a/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolGroupRepository.java b/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolGroupRepository.java deleted file mode 100644 index e24520936..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolGroupRepository.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.repositories; - -import de.learnlib.alex.data.entities.SymbolGroup; -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** - * Repository to persist SymbolGroups. - */ -@Repository -public interface SymbolGroupRepository extends JpaRepository { - - /** - * Find all SymbolGroups in a Project. - * - * @param projectId - * The ID the User the SymbolGroup belongs to. - * @return The SymbolGroups. - */ - List findAllByProject_Id(Long projectId); - - /** - * Find all symbol groups by project and its parent. - * - * @param projectId - * The id of the project. - * @param parentId - * The id of the parent. May be null. - * @return The symbol groups. - */ - List findAllByProject_IdAndParent_id(Long projectId, Long parentId); - - /** - * Find a symbol group by its name and parent ID. - * - * @param projectId - * The ID the project the symbol group belongs to. - * @param parentId - * The ID of the parent group. - * @param name - * The name of the symbol group in the project. - * @return The SymbolGroup or null. - */ - SymbolGroup findOneByProject_IdAndParent_IdAndName(Long projectId, Long parentId, String name); - - /** - * Get the default group of the project which is the one that is created during the project creation. - * - * @param projectId - * The id of the project. - * @return The default symbol group. - */ - SymbolGroup findFirstByProject_IdOrderByIdAsc(Long projectId); -} diff --git a/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolOutputMappingRepository.java b/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolOutputMappingRepository.java deleted file mode 100644 index 9aa7c12c4..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolOutputMappingRepository.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.repositories; - -import de.learnlib.alex.data.entities.SymbolOutputMapping; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface SymbolOutputMappingRepository extends JpaRepository { - - /** - * Delete all values of a symbol parameter by the parameter id. - * - * @param parameterId - * The id of the parameter. - */ - void removeAllByParameter_Id(Long parameterId); -} diff --git a/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolPSymbolStepRepository.java b/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolPSymbolStepRepository.java deleted file mode 100644 index b83af66aa..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolPSymbolStepRepository.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.repositories; - -import de.learnlib.alex.data.entities.SymbolPSymbolStep; -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface SymbolPSymbolStepRepository extends JpaRepository { - - List findAllBypSymbol_Symbol_Id(Long symbolId); - - Long countAllBypSymbol_Symbol_Id(Long symbolId); -} diff --git a/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolParameterRepository.java b/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolParameterRepository.java deleted file mode 100644 index 739f2fcc1..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolParameterRepository.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.repositories; - -import de.learnlib.alex.data.entities.SymbolParameter; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** Repository for symbol parameters. */ -@Repository -public interface SymbolParameterRepository extends JpaRepository { - - void deleteAllBySymbol_Project_Id(Long projectId); -} diff --git a/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolParameterValueRepository.java b/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolParameterValueRepository.java deleted file mode 100644 index 1782e4028..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolParameterValueRepository.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.repositories; - -import de.learnlib.alex.data.entities.SymbolParameterValue; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** The repository for the symbol parameter values. */ -@Repository -public interface SymbolParameterValueRepository extends JpaRepository { - - /** - * Delete all values of a symbol parameter by the parameter id. - * - * @param parameterId - * The id of the parameter. - */ - void removeAllByParameter_Id(Long parameterId); -} diff --git a/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolRepository.java b/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolRepository.java deleted file mode 100644 index 8f5aec4cb..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolRepository.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.repositories; - -import de.learnlib.alex.data.entities.Symbol; -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** - * Repository to persist Symbols. - */ -@Repository -public interface SymbolRepository extends JpaRepository { - - List findAllByIdIn(List ids); - - List findAllByProject_idAndIdIn(Long projectId, List ids); - - Symbol findOneByGroup_IdAndName(Long groupId, String name); - - List findAllByProject_Id(Long projectId); - - List findAllByProject_IdAndHidden(Long projectId, boolean deleted); -} diff --git a/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolStepRepository.java b/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolStepRepository.java deleted file mode 100644 index 0bb163d1e..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/repositories/SymbolStepRepository.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.repositories; - -import de.learnlib.alex.data.entities.SymbolStep; -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** - * The repository for {@link SymbolStep}. - */ -@Repository -public interface SymbolStepRepository extends JpaRepository { - - /** - * Delete all steps by a project ID. - * - * @param projectId - * The ID of the project. - */ - void deleteAllBySymbol_Project_Id(Long projectId); - - /** - * Delete all steps by a symbol ID. - * - * @param symbolId - * The ID of the symbol. - * @param stepIds - * The IDs to delete. - */ - void deleteAllBySymbol_IdAndIdNotIn(Long symbolId, List stepIds); - - /** - * Delete all steps by a symbol ID. - * - * @param symbolId - * The ID of the symbol. - */ - void deleteAllBySymbol_Id(Long symbolId); -} diff --git a/backend/src/main/java/de/learnlib/alex/data/repositories/UploadableFileRepository.java b/backend/src/main/java/de/learnlib/alex/data/repositories/UploadableFileRepository.java deleted file mode 100644 index fc342c9b6..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/repositories/UploadableFileRepository.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.repositories; - -import de.learnlib.alex.data.entities.UploadableFile; -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface UploadableFileRepository extends JpaRepository { - - List findAllByProject_Id(Long projectId); - - UploadableFile findByProject_IdAndName(Long projectId, String name); - - List findAllByIdIn(List fileIds); - - void deleteAllByProject_Id(Long projectId); -} diff --git a/backend/src/main/java/de/learnlib/alex/data/rest/CounterResource.java b/backend/src/main/java/de/learnlib/alex/data/rest/CounterResource.java deleted file mode 100644 index 11b719032..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/rest/CounterResource.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.rest; - -import de.learnlib.alex.data.dao.CounterDAO; -import de.learnlib.alex.data.entities.Counter; -import de.learnlib.alex.security.AuthContext; -import java.util.Collections; -import java.util.List; -import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * Resource to read and delete Counters. - */ -@RestController() -@RequestMapping("/rest/projects/{projectId}/counters") -public class CounterResource { - - private final AuthContext authContext; - private final CounterDAO counterDAO; - - @Autowired - public CounterResource(AuthContext authContext, CounterDAO counterDAO) { - this.authContext = authContext; - this.counterDAO = counterDAO; - } - - /** - * Get all counters of a project. - * - * @param projectId - * The Project ID. - * @return A List of the counters within the project. This list can be empty. - */ - @GetMapping( - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> getAllCounters(@PathVariable("projectId") Long projectId) { - final var user = authContext.getUser(); - final var counters = counterDAO.getAll(user, projectId); - return ResponseEntity.ok(counters); - } - - /** - * Creates a new counter. - * - * @param projectId - * The id of the project. - * @param counter - * The counter to create. - * @return The created counter. - */ - @PostMapping( - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity createCounter( - @PathVariable("projectId") Long projectId, - @RequestBody Counter counter - ) { - final var user = authContext.getUser(); - final var createdCounter = counterDAO.create(user, projectId, counter); - return ResponseEntity.status(HttpStatus.CREATED).body(createdCounter); - } - - /** - * Update the value of a counter. - * - * @param projectId - * The id of the project. - * @param counterId - * The id of the counter. - * @param counter - * The updated counter to update. - * @return The updated counter. - */ - @PutMapping( - value = "/{counterId}", - produces = MediaType.APPLICATION_JSON, - consumes = MediaType.APPLICATION_JSON - ) - public ResponseEntity updateCounter( - @PathVariable("projectId") Long projectId, - @PathVariable("counterId") Long counterId, - @RequestBody Counter counter - ) { - final var user = authContext.getUser(); - final var updatedCounter = counterDAO.update(user, projectId, counterId, counter); - return ResponseEntity.ok(updatedCounter); - } - - /** - * Delete one counter. - * - * @param projectId - * The Project ID. - * @param counterId - * The id of the counter to remove. - * @return Nothing if everything went OK. - */ - @DeleteMapping( - value = "/{counterId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity deleteCounter( - @PathVariable("projectId") Long projectId, - @PathVariable("counterId") Long counterId - ) { - final var user = authContext.getUser(); - counterDAO.delete(user, projectId, Collections.singletonList(counterId)); - return ResponseEntity.noContent().build(); - } - - /** - * Delete multiple counters. - * - * @param projectId - * The Project ID. - * @param counterIds - * The ids of the counters to remove. - * @return Nothing if everything went OK. - */ - @DeleteMapping( - value = "/batch/{counterIds}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity deleteCounter( - @PathVariable("projectId") Long projectId, - @PathVariable("counterIds") List counterIds - ) { - final var user = authContext.getUser(); - counterDAO.delete(user, projectId, counterIds); - return ResponseEntity.noContent().build(); - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/rest/FileResource.java b/backend/src/main/java/de/learnlib/alex/data/rest/FileResource.java deleted file mode 100644 index afc8d70c8..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/rest/FileResource.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.rest; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.dao.FileDAO; -import de.learnlib.alex.data.entities.UploadableFile; -import de.learnlib.alex.security.AuthContext; -import java.io.File; -import java.io.IOException; -import java.util.List; -import javax.validation.ValidationException; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.multipart.MultipartFile; - -/** - * REST API to manage files. - */ -@RestController -@RequestMapping("/rest/projects/{projectId}/files") -public class FileResource { - - private final AuthContext authContext; - private final FileDAO fileDAO; - - @Autowired - public FileResource(AuthContext authContext, FileDAO fileDAO) { - this.authContext = authContext; - this.fileDAO = fileDAO; - } - - /** - * Uploads a new file to the corresponding upload directory uploads/{userId}/{projectId}/{filename}. - * - * @param projectId - * The id of the project the file belongs to. - * @param fileToUpload - * The file to upload. - * @return The HTTP ResponseEntity with the file object on success. - */ - @PostMapping( - value = "/upload", - consumes = MediaType.MULTIPART_FORM_DATA, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity uploadFile( - @PathVariable("projectId") Long projectId, - @RequestParam("file") MultipartFile fileToUpload - ) { - final User user = authContext.getUser(); - - try { - final UploadableFile file = fileDAO.create(user, projectId, fileToUpload); - return ResponseEntity.ok(file); - } catch (IOException | IllegalStateException e) { - throw new ValidationException(e); - } - } - - /** - * Downloads a file. - * - * @param projectId - * The id of the project. - * @param fileId - * The ID of the file. - * @return The file as blob. - */ - @GetMapping( - value = "/{fileId}/download" - ) - public ResponseEntity downloadFile(@PathVariable("projectId") Long projectId, - @PathVariable("fileId") Long fileId) { - final User user = authContext.getUser(); - final File file = fileDAO.getFile(user, projectId, fileId); - - final Resource resource = new FileSystemResource(file); - return ResponseEntity.ok() - .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getName() + "\"") - .body(resource); - } - - /** - * Get all available files of a project. - * - * @param projectId - * The id of the project. - * @return The list of all files of the project. - */ - @GetMapping( - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity getAllFiles(@PathVariable("projectId") Long projectId) { - final User user = authContext.getUser(); - final List files = fileDAO.getAll(user, projectId); - return ResponseEntity.ok(files); - } - - /** - * Delete a single file from the project directory. - * - * @param projectId - * The id of the project. - * @param fileId - * The ID of the file. - * @return Status 204 No Content on success. - */ - @DeleteMapping( - value = "/{fileId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity deleteFile(@PathVariable("projectId") Long projectId, @PathVariable("fileId") Long fileId) { - final User user = authContext.getUser(); - fileDAO.delete(user, projectId, fileId); - return ResponseEntity.noContent().build(); - } - - @DeleteMapping( - value = "/batch/{fileIds}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity deleteFiles(@PathVariable("projectId") Long projectId, @PathVariable("fileIds") List fileIds) { - final User user = authContext.getUser(); - fileDAO.delete(user, projectId, fileIds); - return ResponseEntity.noContent().build(); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/rest/ProjectEnvironmentResource.java b/backend/src/main/java/de/learnlib/alex/data/rest/ProjectEnvironmentResource.java deleted file mode 100644 index fee53d805..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/rest/ProjectEnvironmentResource.java +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.rest; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.common.exceptions.RestException; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.dao.ProjectEnvironmentDAO; -import de.learnlib.alex.data.dao.SymbolDAO; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.OutputsJob; -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.data.entities.ProjectEnvironmentVariable; -import de.learnlib.alex.data.entities.ProjectUrl; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.learning.entities.ReadOutputConfig; -import de.learnlib.alex.learning.services.SULUtilsService; -import de.learnlib.alex.learning.services.LearnerService; -import de.learnlib.alex.security.AuthContext; -import java.time.Duration; -import java.time.Instant; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; -import javax.validation.ValidationException; -import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/rest/projects/{projectId}/environments") -public class ProjectEnvironmentResource { - - private final AuthContext authContext; - private final ProjectEnvironmentDAO environmentDAO; - private final ProjectDAO projectDAO; - private final SymbolDAO symbolDAO; - private final SULUtilsService sulUtils; - private final Map outputsJobMap = new ConcurrentHashMap<>(); - - @Autowired - public ProjectEnvironmentResource( - AuthContext authContext, - ProjectEnvironmentDAO environmentDAO, - @Lazy ProjectDAO projectDAO, - SymbolDAO symbolDAO, - SULUtilsService sulUtils - ) { - this.authContext = authContext; - this.environmentDAO = environmentDAO; - this.projectDAO = projectDAO; - this.symbolDAO = symbolDAO; - this.sulUtils = sulUtils; - } - - @PostMapping( - value = "/{environmentId}/outputs/jobs", - produces = MediaType.APPLICATION_JSON, - consumes = MediaType.APPLICATION_JSON - ) - public ResponseEntity getOutputs( - @PathVariable("projectId") Long projectId, - @PathVariable("environmentId") Long environmentId, - @RequestBody ReadOutputConfig config - ) { - final var user = authContext.getUser(); - final var env = environmentDAO.getByID(user, environmentId); - - if (config.getSymbols().isEmpty()) { - throw new ValidationException("You have to specify at least one symbol."); - } - - final var project = projectDAO.getByID(user, projectId); - - final var pResetSymbol = config.getPreSymbol(); - if (pResetSymbol == null) { - throw new NotFoundException("No reset symbol specified!"); - } - - final var resetSymbol = symbolDAO.get(user, projectId, pResetSymbol.getSymbol().getId()); - config.getPreSymbol().setSymbol(resetSymbol); - - final var symbolIds = config.getSymbols().stream() - .map(ps -> ps.getSymbol().getId()) - .collect(Collectors.toList()); - final var symbols = symbolDAO.getByIds(user, projectId, symbolIds); - final var symbolMap = new HashMap(); - symbols.forEach(s -> symbolMap.put(s.getId(), s)); - config.getSymbols().forEach(ps -> ps.setSymbol(symbolMap.get(ps.getSymbol().getId()))); - - final var job = new OutputsJob(); - job.id = UUID.randomUUID().toString(); - job.startedAt = ZonedDateTime.now(); - job.projectId = projectId; - job.environmentId = environmentId; - - outputsJobMap.put(job.id, job); - new Thread(() -> { - try { - final var outputs = sulUtils.getSystemOutputs(user, project, env, config).stream() - .map(ExecuteResult::getOutput) - .toList(); - job.finishedAt = ZonedDateTime.now(); - job.success = true; - job.outputs = outputs; - } catch (Exception e) { - job.finishedAt = ZonedDateTime.now(); - job.message = e.getMessage(); - job.success = false; - } - }).start(); - - return ResponseEntity.ok(job); - } - - @GetMapping( - value = "/{environmentId}/outputs/jobs/{jobId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity getOutputs( - @PathVariable("projectId") Long projectId, - @PathVariable("environmentId") Long environmentId, - @PathVariable("jobId") String jobId - ) { - final var user = authContext.getUser(); - final var env = environmentDAO.getByID(user, environmentId); - final var project = projectDAO.getByID(user, projectId); - - if (!outputsJobMap.containsKey(jobId)) { - throw new RestException(HttpStatus.NOT_FOUND, "The job does not exist (anymore)."); - } - - final var job = outputsJobMap.get(jobId); - if (!job.projectId.equals(project.getId())) { - throw new RestException(HttpStatus.FORBIDDEN, "You are not allowed to access the job."); - } - - return ResponseEntity.ok(job); - } - - @GetMapping( - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> getAll(@PathVariable("projectId") Long projectId) { - final User user = authContext.getUser(); - final List envs = environmentDAO.getAll(user, projectId); - return ResponseEntity.ok(envs); - } - - @PostMapping( - produces = MediaType.APPLICATION_JSON, - consumes = MediaType.APPLICATION_JSON - ) - public ResponseEntity create( - @PathVariable("projectId") Long projectId, - @RequestBody ProjectEnvironment env - ) { - final User user = authContext.getUser(); - final ProjectEnvironment createdEnv = environmentDAO.create(user, projectId, env); - return ResponseEntity.status(HttpStatus.CREATED).body(createdEnv); - } - - @DeleteMapping( - value = "/{environmentId}" - ) - public ResponseEntity delete( - @PathVariable("projectId") Long projectId, - @PathVariable("environmentId") Long environmentId - ) { - final User user = authContext.getUser(); - environmentDAO.delete(user, projectId, environmentId); - return ResponseEntity.noContent().build(); - } - - @PutMapping( - value = "/{environmentId}", - produces = MediaType.APPLICATION_JSON, - consumes = MediaType.APPLICATION_JSON - ) - public ResponseEntity update( - @PathVariable("projectId") Long projectId, - @PathVariable("environmentId") Long environmentId, - @RequestBody ProjectEnvironment environment - ) { - final User user = authContext.getUser(); - final ProjectEnvironment updatedEnv = environmentDAO.update(user, projectId, environmentId, environment); - return ResponseEntity.ok(updatedEnv); - } - - @PostMapping( - value = "/{environmentId}/urls", - produces = MediaType.APPLICATION_JSON, - consumes = MediaType.APPLICATION_JSON - ) - public ResponseEntity> createUrl( - @PathVariable("projectId") Long projectId, - @PathVariable("environmentId") Long environmentId, - @RequestBody ProjectUrl url - ) { - final User user = authContext.getUser(); - final List createdUrls = environmentDAO.createUrls(user, projectId, environmentId, url); - return ResponseEntity.status(HttpStatus.CREATED).body(createdUrls); - } - - @DeleteMapping( - value = "/{environmentId}/urls/{urlId}" - ) - public ResponseEntity deleteUrl( - @PathVariable("projectId") Long projectId, - @PathVariable("environmentId") Long environmentId, - @PathVariable("urlId") Long urlId - ) { - final User user = authContext.getUser(); - environmentDAO.deleteUrl(user, projectId, environmentId, urlId); - return ResponseEntity.noContent().build(); - } - - @PutMapping( - value = "/{environmentId}/urls/{urlId}", - produces = MediaType.APPLICATION_JSON, - consumes = MediaType.APPLICATION_JSON - ) - public ResponseEntity> updateUrl( - @PathVariable("projectId") Long projectId, - @PathVariable("environmentId") Long environmentId, - @PathVariable("urlId") Long urlId, - @RequestBody ProjectUrl url - ) { - final User user = authContext.getUser(); - final List updatedUrls = environmentDAO.updateUrls(user, projectId, environmentId, urlId, url); - return ResponseEntity.ok(updatedUrls); - } - - @PostMapping( - value = "/{environmentId}/variables", - produces = MediaType.APPLICATION_JSON, - consumes = MediaType.APPLICATION_JSON - ) - public ResponseEntity createVariable( - @PathVariable("projectId") Long projectId, - @PathVariable("environmentId") Long environmentId, - @RequestBody ProjectEnvironmentVariable variable - ) { - final var user = authContext.getUser(); - final var createdVariable = environmentDAO.createVariable(user, projectId, environmentId, variable); - return ResponseEntity.status(HttpStatus.CREATED).body(createdVariable); - } - - @DeleteMapping( - value = "/{environmentId}/variables/{varId}" - ) - public ResponseEntity deleteVariable( - @PathVariable("projectId") Long projectId, - @PathVariable("environmentId") Long environmentId, - @PathVariable("varId") Long varId - ) { - final User user = authContext.getUser(); - environmentDAO.deleteVariable(user, projectId, environmentId, varId); - return ResponseEntity.noContent().build(); - } - - @PutMapping( - value = "/{environmentId}/variables/{varId}", - produces = MediaType.APPLICATION_JSON, - consumes = MediaType.APPLICATION_JSON - ) - public ResponseEntity updateVariable( - @PathVariable("projectId") Long projectId, - @PathVariable("environmentId") Long environmentId, - @PathVariable("varId") Long varId, - @RequestBody ProjectEnvironmentVariable variable - ) { - final var user = authContext.getUser(); - final var updatedVariable = environmentDAO.updateVariable(user, projectId, environmentId, varId, variable); - return ResponseEntity.ok(updatedVariable); - } - - @Scheduled(fixedDelay = 300000) - public void removeOldOutputJobs() { - final var now = ZonedDateTime.now(); - new ArrayList<>(outputsJobMap.values()).stream() - .filter(job -> job.finishedAt != null && now.minus(Duration.ofMinutes(5)).isAfter(job.startedAt)) - .forEach(job -> outputsJobMap.remove(job.id)); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/rest/ProjectResource.java b/backend/src/main/java/de/learnlib/alex/data/rest/ProjectResource.java deleted file mode 100644 index abdd806f6..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/rest/ProjectResource.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.rest; - -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.entities.CreateProjectForm; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.export.ExportableEntity; -import de.learnlib.alex.data.entities.export.ProjectExportableEntity; -import de.learnlib.alex.data.events.ProjectEvent; -import de.learnlib.alex.data.services.export.ProjectExporter; -import de.learnlib.alex.security.AuthContext; -import de.learnlib.alex.webhooks.services.WebhookService; -import java.util.List; -import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/rest/projects") -public class ProjectResource { - - private final AuthContext authContext; - private final ProjectDAO projectDAO; - private final WebhookService webhookService; - private final ProjectExporter projectExporter; - - @Autowired - public ProjectResource(AuthContext authContext, - ProjectDAO projectDAO, - WebhookService webhookService, - ProjectExporter projectExporter) { - this.authContext = authContext; - this.projectDAO = projectDAO; - this.webhookService = webhookService; - this.projectExporter = projectExporter; - } - - /** - * Create a new Project. - * - * @param project - * The project to create. - * @return On success the added project (enhanced with information from the DB); an error message on failure. - */ - @PostMapping( - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity create(@RequestBody @Validated CreateProjectForm project) { - final var user = authContext.getUser(); - final var createdProject = projectDAO.create(user, project); - webhookService.fireEvent(user, new ProjectEvent.Created(createdProject)); - return ResponseEntity.status(HttpStatus.CREATED).body(createdProject); - } - - /** - * Get a list of all the projects owned by the user of the request. - * - * @return All projects in a list. This list can be empty. - */ - @GetMapping( - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> getAll() { - final var user = authContext.getUser(); - final var projects = projectDAO.getAll(user); - return ResponseEntity.ok(projects); - } - - /** - * Get a specific project. - * - * @param projectId - * The ID of the project. - * @return The project or an error message. - */ - @GetMapping( - value = "/{projectId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity get(@PathVariable("projectId") Long projectId) { - final var user = authContext.getUser(); - final var project = projectDAO.getByID(user, projectId); - return ResponseEntity.ok(project); - } - - /** - * Update a specific project. - * - * @param projectId - * The ID of the project. - * @param project - * The new values - * @return On success the updated project (enhanced with information from the DB); an error message on failure. - */ - @PutMapping( - value = "/{projectId}", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity update(@PathVariable("projectId") Long projectId, @RequestBody Project project) { - final var user = authContext.getUser(); - final var updatedProject = projectDAO.update(user, projectId, project); - webhookService.fireEvent(user, new ProjectEvent.Updated(updatedProject)); - return ResponseEntity.ok(updatedProject); - } - - /** - * Delete a specific project. - * - * @param projectId - * The ID of the project. - * @return On success no content will be returned; an error message on failure. - */ - @DeleteMapping( - value = "/{projectId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity delete(@PathVariable("projectId") Long projectId) { - final var user = authContext.getUser(); - projectDAO.delete(user, projectId); - webhookService.fireEvent(user, new ProjectEvent.Deleted(projectId)); - return ResponseEntity.noContent().build(); - } - - /** - * Delete multiple projects at once. - * - * @param projectIds - * The IDs of the projects to delete. - * @return 204 No content on success - */ - @DeleteMapping( - value = "/batch/{projectIds}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity delete(@PathVariable("projectIds") List projectIds) { - final var user = authContext.getUser(); - projectDAO.delete(user, projectIds); - return ResponseEntity.noContent().build(); - } - - /** - * Export a project as JSON document. - * - * @param projectId - * The ID of the project to export. - * @return The exported project. - * @throws Exception - * If something goes wrong. - */ - @PostMapping( - value = "/{projectId}/export", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity exportProject(@PathVariable("projectId") Long projectId) throws Exception { - final var user = authContext.getUser(); - final var export = projectExporter.export(user, projectId); - return ResponseEntity.ok(export); - } - - /** - * Import a project, its symbols and tests. - * - * @param project - * The project to import - * @return the imported project. - */ - @PostMapping( - value = "/import", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity importProject(@RequestBody ProjectExportableEntity project) { - final var user = authContext.getUser(); - final var importedProject = projectDAO.importProject(user, project); - webhookService.fireEvent(user, new ProjectEvent.Created(importedProject)); - return ResponseEntity.status(HttpStatus.CREATED).body(importedProject); - } - - @PostMapping( - value = "/{projectId}/owners", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity addOwners( - @PathVariable("projectId") Long projectId, - @RequestBody List ownerIds - ) { - final var user = authContext.getUser(); - final var updatedProject = projectDAO.addOwners(user, projectId, ownerIds); - return ResponseEntity.ok(updatedProject); - } - - @PostMapping( - value = "/{projectId}/members", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity addMembers( - @PathVariable("projectId") Long projectId, - @RequestBody List memberIds - ) { - final var user = authContext.getUser(); - final var updatedProject = projectDAO.addMembers(user, projectId, memberIds); - return ResponseEntity.ok(updatedProject); - } - - @DeleteMapping( - value = "/{projectId}/owners/{ownerIds}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity removeOwner( - @PathVariable("projectId") Long projectId, - @PathVariable("ownerIds") List ownerIds - ) { - final var user = authContext.getUser(); - final var updatedProject = projectDAO.removeOwners(user, projectId, ownerIds); - return ResponseEntity.ok(updatedProject); - } - - @DeleteMapping( - value = "/{projectId}/members/{memberIds}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity removeMember( - @PathVariable("projectId") Long projectId, - @PathVariable("memberIds") List memberIds - ) { - final var user = authContext.getUser(); - final var updatedProject = projectDAO.removeMembers(user, projectId, memberIds); - return ResponseEntity.ok(updatedProject); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/rest/SymbolGroupResource.java b/backend/src/main/java/de/learnlib/alex/data/rest/SymbolGroupResource.java deleted file mode 100644 index 48c880c11..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/rest/SymbolGroupResource.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.rest; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.dao.SymbolGroupDAO; -import de.learnlib.alex.data.entities.SymbolGroup; -import de.learnlib.alex.data.events.SymbolGroupEvent; -import de.learnlib.alex.security.AuthContext; -import de.learnlib.alex.webhooks.services.WebhookService; -import java.util.List; -import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * REST API to manage groups. - */ -@RestController -@RequestMapping("/rest/projects/{projectId}/groups") -public class SymbolGroupResource { - - private final AuthContext authContext; - private final SymbolGroupDAO symbolGroupDAO; - private final WebhookService webhookService; - - @Autowired - public SymbolGroupResource(AuthContext authContext, - SymbolGroupDAO symbolGroupDAO, - WebhookService webhookService) { - this.authContext = authContext; - this.symbolGroupDAO = symbolGroupDAO; - this.webhookService = webhookService; - } - - /** - * Create a new group. - * - * @param projectId - * The ID of the project. - * @param group - * The group to create. - * @return On success the added group (enhanced with information from the DB); an error message on failure. - */ - @PostMapping( - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity createGroup( - @PathVariable("projectId") Long projectId, - @RequestBody SymbolGroup group - ) { - final User user = authContext.getUser(); - final var createdGroup = symbolGroupDAO.create(user, projectId, group); - webhookService.fireEvent(user, new SymbolGroupEvent.Created(createdGroup)); - return ResponseEntity.status(HttpStatus.CREATED).body(createdGroup); - } - - /** - * Create multiple symbol groups including symbols at once. - * - * @param projectId - * The ID of the project. - * @param groups - * The groups to create. - * @return The created groups. - */ - @PostMapping( - value = "/batch", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> createGroups( - @PathVariable("projectId") Long projectId, - @RequestBody List groups - ) { - final User user = authContext.getUser(); - final List createdGroups = symbolGroupDAO.create(user, projectId, groups); - webhookService.fireEvent(user, new SymbolGroupEvent.CreatedMany(createdGroups)); - return ResponseEntity.status(HttpStatus.CREATED).body(createdGroups); - } - - /** - * Get a list of all groups within on projects. - * - * @param projectId - * The ID of the project. - * @return All groups in a list. If the project contains no groups the list will be empty. - */ - @GetMapping( - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> getAll(@PathVariable("projectId") Long projectId) { - final User user = authContext.getUser(); - final List groups = symbolGroupDAO.getAll(user, projectId); - return ResponseEntity.ok(groups); - } - - /** - * Get a one group. - * - * @param projectId - * The ID of the project. - * @param groupId - * The ID of the group within the project. - * @return The requested group. - */ - @GetMapping( - value = "/{groupId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity get( - @PathVariable("projectId") Long projectId, - @PathVariable("groupId") Long groupId - ) { - final User user = authContext.getUser(); - final SymbolGroup group = symbolGroupDAO.get(user, projectId, groupId); - return ResponseEntity.ok(group); - } - - /** - * Update a group. - * - * @param projectId - * The ID of the project. - * @param groupId - * The ID of the group within the project. - * @param group - * The new values - * @return On success the updated group (enhanced with information from the DB). - */ - @PutMapping( - value = "/{groupId}", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity update(@PathVariable("projectId") Long projectId, - @PathVariable("groupId") Long groupId, - @RequestBody SymbolGroup group) { - final User user = authContext.getUser(); - final var updatedGroup = symbolGroupDAO.update(user, projectId, groupId, group); - webhookService.fireEvent(user, new SymbolGroupEvent.Updated(updatedGroup)); - return ResponseEntity.ok(updatedGroup); - } - - /** - * Moves a group to another group. - * - * @param projectId - * The id of the project. - * @param groupId - * The id of the group to move. - * @param group - * The group to move with the updated {@link SymbolGroup#getParent()} property. The parent property may be null - * to indicate that the group is moved to the upmost level. - * @return 200 with the updated group. - */ - @PutMapping( - value = "/{groupId}/move", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity move(@PathVariable("projectId") Long projectId, - @PathVariable("groupId") Long groupId, - @RequestBody SymbolGroup group) { - final User user = authContext.getUser(); - final SymbolGroup movedGroup = symbolGroupDAO.move(user, group); - webhookService.fireEvent(user, new SymbolGroupEvent.Moved(movedGroup)); - return ResponseEntity.ok(movedGroup); - } - - /** - * Delete a group. - * - * @param projectId - * The ID of the project. - * @param groupId - * The ID of the group within the project. - * @return On success no content will be returned. - */ - @DeleteMapping( - value = "/{groupId}" - ) - public ResponseEntity delete(@PathVariable("projectId") Long projectId, @PathVariable("groupId") Long groupId) { - final User user = authContext.getUser(); - symbolGroupDAO.delete(user, projectId, groupId); - webhookService.fireEvent(user, new SymbolGroupEvent.Deleted(groupId)); - return ResponseEntity.noContent().build(); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/rest/SymbolParameterResource.java b/backend/src/main/java/de/learnlib/alex/data/rest/SymbolParameterResource.java deleted file mode 100644 index 31a9a85cc..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/rest/SymbolParameterResource.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.rest; - -import de.learnlib.alex.data.dao.SymbolParameterDAO; -import de.learnlib.alex.data.entities.SymbolParameter; -import de.learnlib.alex.security.AuthContext; -import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * The resource for symbol parameters. - */ -@RestController -@RequestMapping("/rest/projects/{projectId}/symbols/{symbolId}/parameters") -public class SymbolParameterResource { - - private final AuthContext authContext; - private final SymbolParameterDAO symbolParameterDAO; - - @Autowired - public SymbolParameterResource(AuthContext authContext, - SymbolParameterDAO symbolParameterDAO) { - this.authContext = authContext; - this.symbolParameterDAO = symbolParameterDAO; - } - - /** - * Create a new parameter for a symbol. - * - * @param projectId - * The id of the project. - * @param symbolId - * The id of the symbol. - * @param parameter - * The parameter to create. - * @return 201 on success. - */ - @PostMapping( - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity create( - @PathVariable("projectId") Long projectId, - @PathVariable("symbolId") Long symbolId, - @RequestBody SymbolParameter parameter - ) { - final var user = authContext.getUser(); - final var createdParameter = symbolParameterDAO.create(user, projectId, symbolId, parameter); - return ResponseEntity.status(HttpStatus.CREATED).body(createdParameter); - } - - /** - * Deletes a symbol parameter. - * - * @param projectId - * The id of the project. - * @param symbolId - * The id of the symbol. - * @param parameterId - * The id of the parameter to delete. - * @return 204 on success. - */ - @DeleteMapping( - value = "/{parameterId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity delete( - @PathVariable("projectId") Long projectId, - @PathVariable("symbolId") Long symbolId, - @PathVariable("parameterId") Long parameterId - ) { - final var user = authContext.getUser(); - symbolParameterDAO.delete(user, projectId, symbolId, parameterId); - return ResponseEntity.noContent().build(); - } - - /** - * Updates a symbol parameter. - * - * @param projectId - * The id of the project. - * @param symbolId - * The id of the symbol. - * @param parameterId - * The id of the parameter to update. - * @param parameter - * The parameter to update. - * @return 200 on success. - */ - @PutMapping( - value = "/{parameterId}", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity update( - @PathVariable("projectId") Long projectId, - @PathVariable("symbolId") Long symbolId, - @PathVariable("parameterId") Long parameterId, - @RequestBody SymbolParameter parameter - ) { - final var user = authContext.getUser(); - final var updatedParameter = symbolParameterDAO.update(user, projectId, symbolId, parameterId, parameter); - return ResponseEntity.ok(updatedParameter); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/rest/SymbolResource.java b/backend/src/main/java/de/learnlib/alex/data/rest/SymbolResource.java deleted file mode 100644 index 550bcf2fe..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/rest/SymbolResource.java +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.rest; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.dao.SymbolDAO; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolUsageResult; -import de.learnlib.alex.data.entities.export.ExportableEntity; -import de.learnlib.alex.data.entities.export.SymbolsExportConfig; -import de.learnlib.alex.data.events.SymbolEvent; -import de.learnlib.alex.data.services.SymbolUsageService; -import de.learnlib.alex.data.services.export.SymbolsExporter; -import de.learnlib.alex.security.AuthContext; -import de.learnlib.alex.webhooks.services.WebhookService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.ws.rs.core.MediaType; -import java.util.Collections; -import java.util.List; - -/** - * REST API to manage the symbols. - */ -@RestController -@RequestMapping("/rest/projects/{projectId}/symbols") -public class SymbolResource { - - private final AuthContext authContext; - private final WebhookService webhookService; - private final SymbolDAO symbolDAO; - private final SymbolUsageService symbolUsageService; - private final SymbolsExporter symbolExporter; - - @Autowired - public SymbolResource(AuthContext authContext, - WebhookService webhookService, - SymbolDAO symbolDAO, - SymbolUsageService symbolUsageService, - SymbolsExporter symbolExporter) { - this.authContext = authContext; - this.webhookService = webhookService; - this.symbolDAO = symbolDAO; - this.symbolUsageService = symbolUsageService; - this.symbolExporter = symbolExporter; - } - - /** - * Create a new Symbol. - * - * @param projectId - * The ID of the project the symbol should belong to. - * @param symbol - * The symbol to add. - * @return On success the added symbol (enhanced with information from the DB); An error message on failure. - */ - @PostMapping( - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity createSymbol(@PathVariable("projectId") Long projectId, @RequestBody Symbol symbol) { - final User user = authContext.getUser(); - final Symbol createdSymbol = symbolDAO.create(user, projectId, symbol); - webhookService.fireEvent(user, new SymbolEvent.Created(createdSymbol)); - return ResponseEntity.status(HttpStatus.CREATED).body(createdSymbol); - } - - /** - * Create a bunch of new Symbols. - * - * @param projectId - * The ID of the project the symbol should belong to. - * @param symbols - * The symbols to add. - * @return On success the added symbols (enhanced with information from the DB); An error message on failure. - */ - @PostMapping( - value = "/batch", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity createSymbols(@PathVariable("projectId") Long projectId, @RequestBody List symbols) { - final User user = authContext.getUser(); - final List createdSymbols = symbolDAO.create(user, projectId, symbols); - webhookService.fireEvent(user, new SymbolEvent.CreatedMany(createdSymbols)); - return ResponseEntity.status(HttpStatus.CREATED).body(createdSymbols); - } - - /** - * Get all the Symbols of a specific Project. - * - * @param projectId - * The ID of the project. - * @return A list of all Symbols belonging to the project. This list can be empty. - */ - @GetMapping( - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> getAll( - @PathVariable("projectId") Long projectId, - @RequestParam(value = "hidden", defaultValue = "false") Boolean hidden - ) { - final var user = authContext.getUser(); - final var symbols = symbolDAO.getAll(user, projectId, hidden); - return ResponseEntity.ok(symbols); - } - - /** - * Get Symbols by a list of ids. - * - * @param projectId - * The ID of the project - * @param symbolIds - * The non-empty list of symbol ids. - * @return A list of the symbols whose ids were given - */ - @GetMapping( - value = "/batch/{symbolIds}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity getByIds(@PathVariable("projectId") Long projectId, @PathVariable("symbolIds") List symbolIds) { - final User user = authContext.getUser(); - final List symbols = symbolDAO.getByIds(user, projectId, symbolIds); - return ResponseEntity.ok(symbols); - } - - /** - * Get a Symbol by its ID. - * - * @param projectId - * The ID of the project. - * @param symbolId - * The ID of the symbol. - * @return A Symbol matching the projectID & ID or a not found ResponseEntity. - */ - @GetMapping( - value = "/{symbolId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity get(@PathVariable("projectId") Long projectId, @PathVariable("symbolId") Long symbolId) { - final User user = authContext.getUser(); - final Symbol symbol = symbolDAO.get(user, projectId, symbolId); - return ResponseEntity.ok(symbol); - } - - @GetMapping( - value = "/{symbolId}/usages", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity getUsages(@PathVariable("projectId") Long projectId, @PathVariable("symbolId") Long symbolId) { - final User user = authContext.getUser(); - final SymbolUsageResult result = symbolUsageService.findUsages(user, projectId, symbolId); - return ResponseEntity.ok(result); - } - - /** - * Update a Symbol. - * - * @param projectId - * The ID of the project. - * @param symbolId - * The ID of the symbol. - * @param symbol - * The new symbol data. - * @return On success the updated symbol (maybe enhanced with information from the DB); An error message on failure. - */ - @PutMapping( - value = "/{symbolId}", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity update(@PathVariable("projectId") Long projectId, - @PathVariable("symbolId") Long symbolId, - @RequestBody Symbol symbol) { - final User user = authContext.getUser(); - final Symbol updatedSymbol = symbolDAO.update(user, projectId, symbol); - webhookService.fireEvent(user, new SymbolEvent.Updated(updatedSymbol)); - return ResponseEntity.ok(updatedSymbol); - } - - /** - * Move a Symbol to a new group. - * - * @param projectId - * The ID of the project. - * @param symbolId - * The ID of the symbol. - * @param groupId - * The ID of the new group. - * @return On success the moved symbol (enhanced with information from the DB); An error message on failure. - */ - @PutMapping( - value = "/{symbolId}/moveTo/{groupId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity moveSymbolToGroup(@PathVariable("projectId") Long projectId, - @PathVariable("symbolId") Long symbolId, - @PathVariable("groupId") Long groupId) { - final User user = authContext.getUser(); - final Symbol movedSymbol = symbolDAO.move(user, projectId, symbolId, groupId); - webhookService.fireEvent(user, new SymbolEvent.Updated(movedSymbol)); - return ResponseEntity.ok(movedSymbol); - } - - /** - * Move a bunch of Symbols to a new group. - * - * @param projectId - * The ID of the project. - * @param symbolIds - * The ID of the symbols. - * @param groupId - * The ID of the new group. - * @return On success the moved symbols (enhanced with information from the DB); An error message on failure. - */ - @PutMapping( - value = "/batch/{symbolIds}/moveTo/{groupId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity moveSymbolsToGroup(@PathVariable("projectId") Long projectId, - @PathVariable("symbolIds") List symbolIds, - @PathVariable("groupId") Long groupId) { - final User user = authContext.getUser(); - final List movedSymbols = symbolDAO.move(user, projectId, symbolIds, groupId); - webhookService.fireEvent(user, new SymbolEvent.UpdatedMany(movedSymbols)); - return ResponseEntity.ok(movedSymbols); - } - - /** - * Mark one symbol as hidden. - * - * @param projectId - * The ID of the project. - * @param symbolId - * The ID of the symbol to hide. - * @return On success no content will be returned; an error message on failure. - */ - @PostMapping( - value = "/{symbolId}/hide", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity hide(@PathVariable("projectId") Long projectId, @PathVariable("symbolId") Long symbolId) { - final User user = authContext.getUser(); - final Symbol archivedSymbol = symbolDAO.hide(user, projectId, Collections.singletonList(symbolId)).get(0); - webhookService.fireEvent(user, new SymbolEvent.Updated(archivedSymbol)); - return ResponseEntity.ok(archivedSymbol); - } - - /** - * Mark a bunch of symbols as hidden. - * - * @param projectId - * The ID of the project. - * @param symbolIds - * The IDs of the symbols to hide. - * @return On success no content will be returned; an error message on failure.. - */ - @PostMapping( - value = "/batch/{symbolIds}/hide", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity hide(@PathVariable("projectId") Long projectId, @PathVariable("symbolIds") List symbolIds) { - final User user = authContext.getUser(); - final List archivedSymbols = symbolDAO.hide(user, projectId, symbolIds); - webhookService.fireEvent(user, new SymbolEvent.UpdatedMany(archivedSymbols)); - return ResponseEntity.ok(archivedSymbols); - } - - /** - * Permanently delete a symbol. - * - * @param projectId - * The ID of the project. - * @param symbolId - * The ID of the symbol. - * @return 204 No content if the symbol could be deleted. - */ - @DeleteMapping( - value = "/{symbolId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity delete(@PathVariable("projectId") Long projectId, @PathVariable("symbolId") Long symbolId) { - final User user = authContext.getUser(); - symbolDAO.delete(user, projectId, symbolId); - webhookService.fireEvent(user, new SymbolEvent.Deleted(symbolId)); - return ResponseEntity.noContent().build(); - } - - /** - * Permanently delete multiple symbols at once. - * - * @param projectId - * The ID of the project. - * @param symbolIds - * The IDs of the symbols to delete. - * @return 204 on success. - */ - @DeleteMapping( - value = "/batch/{symbolIds}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity delete(@PathVariable("projectId") Long projectId, @PathVariable("symbolIds") List symbolIds) { - final User user = authContext.getUser(); - symbolDAO.delete(user, projectId, symbolIds); - webhookService.fireEvent(user, new SymbolEvent.DeletedMany(symbolIds)); - return ResponseEntity.noContent().build(); - } - - /** - * Remove the hidden flag from a symbol. - * - * @param projectId - * The ID of the project. - * @param symbolId - * The ID of the symbol to show. - * @return On success no content will be returned; an error message on failure. - */ - @PostMapping( - value = "/{symbolId}/show", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity show(@PathVariable("projectId") Long projectId, @PathVariable("symbolId") Long symbolId) { - final User user = authContext.getUser(); - symbolDAO.show(user, projectId, Collections.singletonList(symbolId)); - final Symbol symbol = symbolDAO.get(user, projectId, symbolId); - webhookService.fireEvent(user, new SymbolEvent.Updated(symbol)); - return ResponseEntity.ok(symbol); - } - - /** - * Remove the hidden flag from a bunch of symbols. - * - * @param projectId - * The ID of the project. - * @param symbolIds - * The IDs of the symbols to show. - * @return On success no content will be returned; an error message on failure. - */ - @PostMapping( - value = "/batch/{symbolIds}/show", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity show(@PathVariable("projectId") Long projectId, @PathVariable("symbolIds") List symbolIds) { - final User user = authContext.getUser(); - symbolDAO.show(user, projectId, symbolIds); - final List symbols = symbolDAO.getByIds(user, projectId, symbolIds); - webhookService.fireEvent(user, new SymbolEvent.UpdatedMany(symbols)); - return ResponseEntity.ok(symbols); - } - - /** - * Export symbols as JSON document. - * - * @param projectId - * The ID of the project. - * @param config - * The configuration for the export. - * @return The JSON document that contains the symbols. - * @throws Exception - * If something goes wrong. - */ - @PostMapping( - value = "/export", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity export(@PathVariable("projectId") Long projectId, - @RequestBody SymbolsExportConfig config) throws Exception { - final User user = authContext.getUser(); - final ExportableEntity symbols = symbolExporter.export(user, projectId, config); - return ResponseEntity.ok(symbols); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/services/SymbolUsageService.java b/backend/src/main/java/de/learnlib/alex/data/services/SymbolUsageService.java deleted file mode 100644 index f8a24ef41..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/services/SymbolUsageService.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.services; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.dao.SymbolDAO; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolPSymbolStep; -import de.learnlib.alex.data.entities.SymbolUsageResult; -import de.learnlib.alex.data.repositories.SymbolPSymbolStepRepository; -import de.learnlib.alex.learning.entities.LearnerSetup; -import de.learnlib.alex.learning.repositories.LearnerSetupRepository; -import de.learnlib.alex.testing.entities.TestCase; -import de.learnlib.alex.testing.entities.TestCaseStep; -import de.learnlib.alex.testing.repositories.TestCaseStepRepository; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(rollbackFor = Exception.class, readOnly = true) -public class SymbolUsageService { - - private final SymbolDAO symbolDAO; - private final SymbolPSymbolStepRepository symbolPSymbolStepRepository; - private final TestCaseStepRepository testCaseStepRepository; - private final LearnerSetupRepository learnerSetupRepository; - - @Autowired - public SymbolUsageService( - SymbolDAO symbolDAO, - SymbolPSymbolStepRepository symbolPSymbolStepRepository, - TestCaseStepRepository testCaseStepRepository, - LearnerSetupRepository learnerSetupRepository - ) { - this.symbolDAO = symbolDAO; - this.symbolPSymbolStepRepository = symbolPSymbolStepRepository; - this.testCaseStepRepository = testCaseStepRepository; - this.learnerSetupRepository = learnerSetupRepository; - } - - public SymbolUsageResult findUsages(User user, Long projectId, Long symbolId) { - final Symbol symbol = symbolDAO.get(user, projectId, symbolId); - - final SymbolUsageResult usageResult = new SymbolUsageResult(); - - final Set foundInSymbols = symbolPSymbolStepRepository.findAllBypSymbol_Symbol_Id(symbol.getId()).stream() - .map(SymbolPSymbolStep::getSymbol) - .collect(Collectors.toSet()); - foundInSymbols.forEach(s -> s.setSteps(new ArrayList<>())); - usageResult.setSymbols(foundInSymbols); - - final Set foundInTestCases = testCaseStepRepository.findAllBypSymbol_Symbol_Id(symbol.getId()).stream() - .map(TestCaseStep::getTestCase) - .collect(Collectors.toSet()); - - foundInTestCases.forEach(tc -> tc.setSteps(new ArrayList<>())); - usageResult.setTestCases(foundInTestCases); - - final Set foundInLearnerSetup = new HashSet<>(); - final List setups = learnerSetupRepository.findAllByProject_Id(symbol.getProjectId()); - for (LearnerSetup s : setups) { - if (s.getPreSymbol().getSymbol().getId().equals(symbolId) - || (s.getPostSymbol() != null && s.getPostSymbol().getSymbol().getId().equals(symbolId))) { - foundInLearnerSetup.add(s); - continue; - } - for (ParameterizedSymbol ps : s.getSymbols()) { - if (ps.getSymbol().getId().equals(symbolId)) { - foundInLearnerSetup.add(s); - break; - } - } - } - usageResult.setLearnerSetups(foundInLearnerSetup); - - return usageResult; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/services/export/EntityExporter.java b/backend/src/main/java/de/learnlib/alex/data/services/export/EntityExporter.java deleted file mode 100644 index 9e957997c..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/services/export/EntityExporter.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.services.export; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.springframework.beans.factory.annotation.Value; - -public abstract class EntityExporter { - - /** The version string of ALEX. */ - @Value("${alex.version}") - protected String version; - - /** The object mapper to use for writing the JSON document. */ - protected ObjectMapper om; - - protected EntityExporter() { - this.om = new ObjectMapper(); - } - - /** Ignores 'id' fields in JSON documents. */ - protected abstract static class IgnoreIdFieldMixin { - @JsonIgnore - abstract Long getId(); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/services/export/ProjectExporter.java b/backend/src/main/java/de/learnlib/alex/data/services/export/ProjectExporter.java deleted file mode 100644 index 31c4869cd..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/services/export/ProjectExporter.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.services.export; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.data.entities.ProjectEnvironmentVariable; -import de.learnlib.alex.data.entities.ProjectUrl; -import de.learnlib.alex.data.entities.export.ExportableEntity; -import de.learnlib.alex.data.entities.export.ProjectExportableEntity; -import de.learnlib.alex.data.entities.export.SymbolGroupsExportableEntity; -import de.learnlib.alex.learning.entities.export.LearnerSetupExportableEntity; -import de.learnlib.alex.learning.services.export.LearnerSetupsExporter; -import de.learnlib.alex.learning.services.export.TestExecutionConfigsExporter; -import de.learnlib.alex.modelchecking.entities.export.LtsFormulaSuitesExportableEntity; -import de.learnlib.alex.modelchecking.services.export.LtsFormulaSuitesExporter; -import de.learnlib.alex.testing.entities.export.TestExecutionConfigExportableEntity; -import de.learnlib.alex.testing.entities.export.TestsExportableEntity; -import de.learnlib.alex.testing.services.export.TestsExporter; -import java.util.List; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(rollbackFor = Exception.class, readOnly = true) -public class ProjectExporter extends EntityExporter { - - private final ProjectDAO projectDAO; - private final SymbolsExporter symbolsExporter; - private final TestsExporter testsExporter; - private final LtsFormulaSuitesExporter formulaSuitesExporter; - private final LearnerSetupsExporter learnerSetupsExporter; - private final TestExecutionConfigsExporter testExecutionConfigsExporter; - - @Autowired - public ProjectExporter( - ProjectDAO projectDAO, - SymbolsExporter symbolsExporter, - TestsExporter testsExporter, - LtsFormulaSuitesExporter formulaSuitesExporter, - LearnerSetupsExporter learnerSetupsExporter, - TestExecutionConfigsExporter testExecutionConfigsExporter - ) { - this.projectDAO = projectDAO; - this.symbolsExporter = symbolsExporter; - this.testsExporter = testsExporter; - this.formulaSuitesExporter = formulaSuitesExporter; - this.learnerSetupsExporter = learnerSetupsExporter; - this.testExecutionConfigsExporter = testExecutionConfigsExporter; - } - - public ExportableEntity export(User user, Long projectId) throws Exception { - om.addMixIn(Project.class, IgnoreFieldsForProjectMixin.class); - om.addMixIn(ProjectEnvironment.class, IgnoreFieldsForProjectEnvironmentMixin.class); - om.addMixIn(ProjectUrl.class, IgnoreFieldsForProjectUrlMixin.class); - om.addMixIn(ProjectEnvironmentVariable.class, IgnoreFieldsForProjectVariableMixin.class); - - final var project = projectDAO.getByID(user, projectId); - - final var exportableEntity = new ProjectExportableEntity(version, om.readTree(om.writeValueAsString(project))); - exportableEntity.setGroups(((SymbolGroupsExportableEntity) symbolsExporter.exportAll(user, projectId)).getSymbolGroups()); - exportableEntity.setTests(((TestsExportableEntity) testsExporter.exportAll(user, projectId)).getTests()); - exportableEntity.setFormulaSuites(((LtsFormulaSuitesExportableEntity) formulaSuitesExporter.export(user, projectId)).getFormulaSuites()); - exportableEntity.setLearnerSetups(((LearnerSetupExportableEntity) learnerSetupsExporter.export(user, projectId)).getLearnerSetups()); - exportableEntity.setTestExecutionConfigs(((TestExecutionConfigExportableEntity) testExecutionConfigsExporter.export(user, projectId)).getTestConfigs()); - - return exportableEntity; - } - - private abstract static class IgnoreFieldsForProjectMixin extends IgnoreIdFieldMixin { - @JsonIgnore - abstract Long getUserId(); - - @JsonIgnore - abstract List getMemberIds(); - - @JsonIgnore - abstract List getOwnerIds(); - } - - private abstract static class IgnoreFieldsForProjectEnvironmentMixin extends IgnoreIdFieldMixin { - @JsonIgnore - abstract Long getProjectId(); - } - - private abstract static class IgnoreFieldsForProjectUrlMixin extends IgnoreIdFieldMixin { - @JsonIgnore - abstract Long getEnvironmentId(); - } - - private abstract static class IgnoreFieldsForProjectVariableMixin extends IgnoreFieldsForProjectUrlMixin { - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/services/export/SymbolsExporter.java b/backend/src/main/java/de/learnlib/alex/data/services/export/SymbolsExporter.java deleted file mode 100644 index c23963477..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/services/export/SymbolsExporter.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.services.export; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.dao.SymbolDAO; -import de.learnlib.alex.data.dao.SymbolGroupDAO; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.data.entities.SymbolGroup; -import de.learnlib.alex.data.entities.SymbolParameter; -import de.learnlib.alex.data.entities.SymbolParameterValue; -import de.learnlib.alex.data.entities.SymbolStep; -import de.learnlib.alex.data.entities.export.ExportableEntity; -import de.learnlib.alex.data.entities.export.SymbolGroupsExportableEntity; -import de.learnlib.alex.data.entities.export.SymbolsExportConfig; -import de.learnlib.alex.data.entities.export.SymbolsExportableEntity; -import de.learnlib.alex.data.repositories.SymbolGroupRepository; -import de.learnlib.alex.data.repositories.SymbolRepository; -import java.io.IOException; -import java.util.List; -import java.util.stream.Collectors; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(rollbackFor = Exception.class, readOnly = true) -public class SymbolsExporter extends EntityExporter { - - private final SymbolRepository symbolRepository; - private final SymbolGroupRepository symbolGroupRepository; - private final SymbolGroupDAO symbolGroupDAO; - private final SymbolDAO symbolDAO; - - @Autowired - public SymbolsExporter( - SymbolRepository symbolRepository, - SymbolGroupRepository symbolGroupRepository, - SymbolGroupDAO symbolGroupDAO, - SymbolDAO symbolDAO - ) { - super(); - - this.symbolRepository = symbolRepository; - this.symbolGroupRepository = symbolGroupRepository; - this.symbolGroupDAO = symbolGroupDAO; - this.symbolDAO = symbolDAO; - - om.addMixIn(SymbolGroup.class, IgnoreFieldsForSymbolGroupMixin.class); - om.addMixIn(Symbol.class, IgnoreFieldsForSymbolMixin.class); - om.addMixIn(SymbolParameter.class, IgnoreIdFieldMixin.class); - om.addMixIn(SymbolStep.class, IgnoreFieldsForSymbolStepMixin.class); - om.addMixIn(SymbolParameterValue.class, IgnoreIdFieldMixin.class); - om.addMixIn(SymbolAction.class, IgnoreIdFieldMixin.class); - om.addMixIn(ParameterizedSymbol.class, IgnoreIdFieldMixin.class); - - final SimpleModule module = new SimpleModule(); - module.addSerializer(new ParameterizedSymbolSerializer(om, ParameterizedSymbol.class)); - om.registerModule(module); - } - - public ExportableEntity export(User user, Long projectId, SymbolsExportConfig config) throws Exception { - if (config.isSymbolsOnly()) { - final List symbols = symbolRepository.findAllByProject_idAndIdIn(projectId, config.getSymbolIds()); - for (Symbol s : symbols) { - symbolDAO.checkAccess(user, s.getProject(), s); - } - return new SymbolsExportableEntity(version, om.readTree(om.writeValueAsString(symbols))); - } else { - final List groups = symbolGroupRepository.findAllByProject_IdAndParent_id(projectId, null); - for (SymbolGroup g : groups) { - symbolGroupDAO.checkAccess(user, g.getProject(), g); - } - final List groupsToExport = getExportableGroups(groups, config); - return new SymbolGroupsExportableEntity(version, om.readTree(om.writeValueAsString(groupsToExport))); - } - } - - public ExportableEntity exportAll(User user, Long projectId) throws Exception { - final List groups = symbolGroupRepository.findAllByProject_IdAndParent_id(projectId, null); - for (SymbolGroup g : groups) { - symbolGroupDAO.checkAccess(user, g.getProject(), g); - } - return new SymbolGroupsExportableEntity(version, om.readTree(om.writeValueAsString(groups))); - } - - private List getExportableGroups(List groups, SymbolsExportConfig config) { - return groups.stream().filter(group -> { - group.setSymbols(group.getSymbols().stream() - .filter(s -> config.getSymbolIds().contains(s.getId())) - .collect(Collectors.toSet())); - group.setGroups(getExportableGroups(group.getGroups(), config)); - return !group.getSymbols().isEmpty() || !group.getGroups().isEmpty(); - }).collect(Collectors.toList()); - } - - public static class ParameterizedSymbolSerializer extends StdSerializer { - - private final ObjectMapper om; - - public ParameterizedSymbolSerializer(ObjectMapper om, Class t) { - super(t); - this.om = om; - } - - @Override - public void serialize(ParameterizedSymbol ps, JsonGenerator jgen, SerializerProvider provider) throws IOException { - final ObjectNode symbolNode = om.createObjectNode(); - symbolNode.put("id", ps.getSymbol().getId()); - - jgen.writeStartObject(); - jgen.writeObjectField("parameterValues", ps.getParameterValues()); - jgen.writeObjectField("symbol", symbolNode); - jgen.writeEndObject(); - } - } - - private abstract static class IgnoreFieldsForSymbolGroupMixin extends IgnoreIdFieldMixin { - @JsonIgnore - abstract Long getProjectId(); - - @JsonIgnore - abstract Long getParentId(); - } - - private abstract static class IgnoreFieldsForSymbolMixin extends IgnoreIdFieldMixin { - @JsonIgnore(value = false) - abstract Long getId(); - - @JsonIgnore - abstract Long getProjectId(); - - @JsonIgnore - abstract Long getGroupId(); - - @JsonIgnore - abstract User getLastUpdatedBy(); - } - - private abstract static class IgnoreFieldsForSymbolStepMixin extends IgnoreIdFieldMixin { - @JsonIgnore - abstract Long getPosition(); - - @JsonIgnore - abstract Long getSymbolId(); - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/data/utils/ExecuteScriptUtils.java b/backend/src/main/java/de/learnlib/alex/data/utils/ExecuteScriptUtils.java deleted file mode 100644 index 1f7db80df..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/utils/ExecuteScriptUtils.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package de.learnlib.alex.data.utils; - -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.CounterStoreConnector; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import java.util.HashMap; -import java.util.Map; - -public class ExecuteScriptUtils { - - private ExecuteScriptUtils() { - } - - public static Map> createScriptStore(ConnectorManager connector) { - final VariableStoreConnector variableStore = connector.getConnector(VariableStoreConnector.class); - final CounterStoreConnector counterStore = connector.getConnector(CounterStoreConnector.class); - - final Map> store = new HashMap<>(); - store.put("variables", variableStore.getStore()); - store.put("counters", counterStore.getStore()); - store.put("urls", connector.getEnvironment().getUrlsAsMap()); - store.put("globals", connector.getEnvironment().getVariablesAsMap()); - - return store; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/data/utils/SymbolOutputMappingUtils.java b/backend/src/main/java/de/learnlib/alex/data/utils/SymbolOutputMappingUtils.java deleted file mode 100644 index 1629335c2..000000000 --- a/backend/src/main/java/de/learnlib/alex/data/utils/SymbolOutputMappingUtils.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.utils; - -import de.learnlib.alex.data.entities.SymbolOutputMapping; -import de.learnlib.alex.data.entities.SymbolParameter; -import java.util.ArrayList; -import java.util.List; -import javax.validation.ValidationException; - -public class SymbolOutputMappingUtils { - - private SymbolOutputMappingUtils() { - } - - public static void checkIfMappedNamesAreUnique(List outputMappings) throws ValidationException { - final List stringNames = new ArrayList<>(); - final List counterNames = new ArrayList<>(); - - for (SymbolOutputMapping om : outputMappings) { - final String name = om.getName(); - if (om.getParameter().getParameterType().equals(SymbolParameter.ParameterType.STRING)) { - if (counterNames.contains(name)) { - throw new ValidationException("Names in the data context are not unique: " + name); - } else { - stringNames.add(name); - } - } else { - if (stringNames.contains(name)) { - throw new ValidationException("Names in the data context are not unique: " + name); - } else { - counterNames.add(name); - } - } - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/grid/entities/GridNode.java b/backend/src/main/java/de/learnlib/alex/grid/entities/GridNode.java deleted file mode 100644 index 4f3f62394..000000000 --- a/backend/src/main/java/de/learnlib/alex/grid/entities/GridNode.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.grid.entities; - -import java.util.ArrayList; -import java.util.List; - -public class GridNode { - - public List slots = new ArrayList<>(); -} diff --git a/backend/src/main/java/de/learnlib/alex/grid/entities/GridNodeSlot.java b/backend/src/main/java/de/learnlib/alex/grid/entities/GridNodeSlot.java deleted file mode 100644 index f668711b2..000000000 --- a/backend/src/main/java/de/learnlib/alex/grid/entities/GridNodeSlot.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.grid.entities; - -public class GridNodeSlot { - - public GridNodeSlotStereotype stereotype; -} diff --git a/backend/src/main/java/de/learnlib/alex/grid/entities/GridNodeSlotStereotype.java b/backend/src/main/java/de/learnlib/alex/grid/entities/GridNodeSlotStereotype.java deleted file mode 100644 index 54e46bfc3..000000000 --- a/backend/src/main/java/de/learnlib/alex/grid/entities/GridNodeSlotStereotype.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.grid.entities; - -public class GridNodeSlotStereotype { - - public String browserName; - - public String browserVersion; - - public String platformName; -} diff --git a/backend/src/main/java/de/learnlib/alex/grid/entities/GridStatus.java b/backend/src/main/java/de/learnlib/alex/grid/entities/GridStatus.java deleted file mode 100644 index 1dad468d1..000000000 --- a/backend/src/main/java/de/learnlib/alex/grid/entities/GridStatus.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.grid.entities; - -public class GridStatus { - - public GridStatusValue value; -} diff --git a/backend/src/main/java/de/learnlib/alex/grid/entities/GridStatusValue.java b/backend/src/main/java/de/learnlib/alex/grid/entities/GridStatusValue.java deleted file mode 100644 index 71303de82..000000000 --- a/backend/src/main/java/de/learnlib/alex/grid/entities/GridStatusValue.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.grid.entities; - -import java.util.ArrayList; -import java.util.List; - -public class GridStatusValue { - - public List nodes = new ArrayList<>(); -} diff --git a/backend/src/main/java/de/learnlib/alex/grid/rest/GridResource.java b/backend/src/main/java/de/learnlib/alex/grid/rest/GridResource.java deleted file mode 100644 index 593207c6d..000000000 --- a/backend/src/main/java/de/learnlib/alex/grid/rest/GridResource.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.grid.rest; - -import de.learnlib.alex.common.exceptions.RestException; -import de.learnlib.alex.grid.entities.GridStatus; -import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.client.RestTemplate; - -@RestController() -@RequestMapping("/rest/grid") -public class GridResource { - - @Value("${selenium.grid.host}") - private String gridHost; - - @Value("${selenium.grid.port}") - private String gridPort; - - @GetMapping( - value = "/status", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity getStatus() { - final var url = "http://" + gridHost + ":" + gridPort + "/status"; - final var res = new RestTemplate().getForEntity(url, GridStatus.class); - - if (!res.getStatusCode().equals(HttpStatus.OK)) { - throw new RestException(HttpStatus.BAD_REQUEST, "Failed to get status of the grid"); - } - - return ResponseEntity.ok(res.getBody()); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/dao/LearnerResultDAO.java b/backend/src/main/java/de/learnlib/alex/learning/dao/LearnerResultDAO.java deleted file mode 100644 index a46701281..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/dao/LearnerResultDAO.java +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.dao; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.learning.entities.LearnerResultStep; -import de.learnlib.alex.learning.repositories.LearnerResultRepository; -import de.learnlib.alex.learning.repositories.LearnerResultStepRepository; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; -import javax.persistence.EntityManager; -import javax.validation.ValidationException; - -import de.learnlib.alex.learning.rest.inputs.UpdateLearnerResultInput; -import org.apache.shiro.authz.UnauthorizedException; -import org.hibernate.Hibernate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -/** - * Implementation of a LearnerResultDAO using Spring Data. - */ -@Service -@Transactional(rollbackFor = Exception.class) -public class LearnerResultDAO { - - private final EntityManager entityManager; - private final ProjectDAO projectDAO; - private final LearnerResultRepository learnerResultRepository; - private final LearnerResultStepRepository learnerResultStepRepository; - private final ProjectRepository projectRepository; - private final LearnerSetupDAO learnerSetupDAO; - private final LearnerResultStepDAO learnerResultStepDAO; - - @Autowired - public LearnerResultDAO( - ProjectDAO projectDAO, - LearnerResultRepository learnerResultRepository, - LearnerResultStepRepository learnerResultStepRepository, - ProjectRepository projectRepository, - LearnerSetupDAO learnerSetupDAO, - EntityManager entityManager, - LearnerResultStepDAO learnerResultStepDAO - ) { - this.projectDAO = projectDAO; - this.learnerResultRepository = learnerResultRepository; - this.learnerResultStepRepository = learnerResultStepRepository; - this.projectRepository = projectRepository; - this.learnerSetupDAO = learnerSetupDAO; - this.entityManager = entityManager; - this.learnerResultStepDAO = learnerResultStepDAO; - } - - public LearnerResult create(User user, Long projectId, LearnerResult learnerResult) { - final var project = projectDAO.getByID(user, projectId); - projectDAO.checkAccess(user, project); - - learnerResult.setProject(project); - learnerResult.setExecutedBy(user); - - // get the current highest test no in the project and add 1 for the next id - var highestTestNo = learnerResultRepository.findHighestTestNo(learnerResult.getProjectId()); - if (highestTestNo == null) { - highestTestNo = -1L; - } - - var nextTestNo = highestTestNo + 1; - learnerResult.setTestNo(nextTestNo); - - final LearnerResult createdLearnerResult = learnerResultRepository.save(learnerResult); - initializeLazyRelations(learnerResult); - return createdLearnerResult; - } - - public List getByIDs(User user, Long projectId, List resultIds) { - final var project = projectDAO.getByID(user, projectId); - - final var results = learnerResultRepository.findByIdIn(resultIds); - for (var result : results) { - checkAccess(user, project, result); - initializeLazyRelations(result); - } - - return results; - } - - public List getAll(User user, Long projectId) { - projectDAO.getByID(user, projectId); // access check - - final var results = learnerResultRepository.findByProject_Id(projectId); - results.forEach(this::initializeLazyRelations); - - return results; - } - - public List getAll(User user, Long projectId, List testNos) { - final var project = projectDAO.getByID(user, projectId); // access check - - final var results = learnerResultRepository.findByProject_IdAndTestNoIn(projectId, testNos); - for (var result : results) { - checkAccess(user, project, result); - initializeLazyRelations(result); - } - - return results; - } - - public Page getAll(User user, Long projectId, PageRequest pr) { - projectDAO.getByID(user, projectId); // access check - - final var results = learnerResultRepository.findByProject_Id(projectId, pr); - results.forEach(this::initializeLazyRelations); - - return results; - } - - public LearnerResult getLatest(User user, Long projectId) { - projectDAO.getByID(user, projectId); - - final var result = learnerResultRepository.findFirstByProject_IdOrderByTestNoDesc(projectId); - - if (result != null) { - initializeLazyRelations(result); - return result; - } else { - return null; - } - } - - public LearnerResult getByTestNo(User user, Long projectId, Long testNo) { - final Project project = projectDAO.getByID(user, projectId); // access check - final LearnerResult result = learnerResultRepository.findOneByProject_IdAndTestNo(projectId, testNo); - checkAccess(user, project, result); - - initializeLazyRelations(result); - - return result; - } - - public LearnerResult getByID(User user, Long projectId, Long resultId) { - final Project project = projectDAO.getByID(user, projectId); // access check - final LearnerResult result = learnerResultRepository.getOne(resultId); - checkAccess(user, project, result); - - initializeLazyRelations(result); - - return result; - } - - public List abortActiveLearnerResults() { - final List pendingLearnerProcesses = learnerResultRepository.findAllByStatusIn( - Arrays.asList(LearnerResult.Status.IN_PROGRESS, LearnerResult.Status.PENDING) - ); - pendingLearnerProcesses.forEach(p -> p.setStatus(LearnerResult.Status.ABORTED)); - return learnerResultRepository.saveAll(pendingLearnerProcesses); - } - - public LearnerResult updateStatus(Long resultId, LearnerResult.Status status) { - var result = learnerResultRepository.findById(resultId) - .orElseThrow(() -> new NotFoundException("result not found.")); - - result.setStatus(status); - result = learnerResultRepository.save(result); - - initializeLazyRelations(result); - return result; - } - - public LearnerResult update(Long resultId, LearnerResult result) { - var resultInDB = learnerResultRepository.findById(resultId) - .orElseThrow(() -> new NotFoundException("result not found.")); - - resultInDB.setStatus(result.getStatus()); - resultInDB.setErrorMessage(result.getErrorMessage()); - resultInDB = learnerResultRepository.save(resultInDB); - - initializeLazyRelations(resultInDB); - return resultInDB; - } - - public LearnerResult update(User user, Long projectId, Long testNo, UpdateLearnerResultInput input) { - var project = projectRepository.findById(projectId).orElse(null); - var resultInDB = learnerResultRepository.findOneByProject_IdAndTestNo(projectId, testNo); - checkAccess(user, project, resultInDB); - - resultInDB.setComment(input.comment); - final var updatedResult = learnerResultRepository.save(resultInDB); - - initializeLazyRelations(updatedResult); - return updatedResult; - } - - public LearnerResult copy(User user, Long projectId, Long testNo) { - final var project = projectDAO.getByID(user, projectId); - final var result = learnerResultRepository.findOneByProject_IdAndTestNo(projectId, testNo); - checkAccess(user, project, result); - - final var resultToClone = new LearnerResult(); - resultToClone.setTestNo(learnerResultRepository.findHighestTestNo(projectId) + 1); - resultToClone.setComment(result.getComment()); - resultToClone.setProject(project); - resultToClone.setStatus(result.getStatus()); - resultToClone.setExecutedBy(result.getExecutedBy()); - resultToClone.setErrorMessage(result.getErrorMessage()); - resultToClone.setSetup(learnerSetupDAO.copy(user, projectId, result.getSetup().getId(), false)); - learnerResultRepository.save(resultToClone); - - for (var step : result.getSteps()) { - entityManager.detach(step); - step.setId(null); - step.setResult(resultToClone); - step.setModelCheckingResults(new ArrayList<>()); - resultToClone.getSteps().add(step); - } - - learnerResultStepRepository.saveAll(resultToClone.getSteps()); - learnerResultRepository.save(resultToClone); - - initializeLazyRelations(resultToClone); - - return resultToClone; - } - - public LearnerResult addStep(Long resultId, LearnerResultStep step) { - var result = learnerResultRepository.findById(resultId) - .orElseThrow(() -> new NotFoundException("result not found")); - - step.setStepNo(result.getSteps().size() + 1L); - step.setResult(result); - final var createdStep = learnerResultStepRepository.save(step); - - result.getSteps().add(createdStep); - - final var updatedResult = learnerResultRepository.save(result); - initializeLazyRelations(updatedResult); - - return updatedResult; - } - - public LearnerResult removeSteps(Long resultId, List steps) { - final var result = learnerResultRepository.findById(resultId) - .orElseThrow(() -> new NotFoundException("result not found")); - - final var stepIds = steps.stream() - .map(LearnerResultStep::getId) - .collect(Collectors.toList()); - - learnerResultStepRepository.deleteAllByIdIn(stepIds); - - result.getSteps().removeIf(s -> stepIds.contains(s.getId())); - result.getStatistics().setEqsUsed(result.getSteps().size()); - final var updatedResult = learnerResultRepository.save(result); - - initializeLazyRelations(updatedResult); - return updatedResult; - } - - public void deleteByTestNos(User user, Long projectId, List testNos) { - final var project = projectDAO.getByID(user, projectId); - final var results = learnerResultRepository.findByProject_IdAndTestNoIn(projectId, testNos); - - for (LearnerResult result : results) { - checkAccess(user, project, result); - } - - checkIfResultsCanBeDeleted(results); - - learnerResultRepository.deleteByProject_IdAndTestNoIn(projectId, testNos); - } - - public void initializeLazyRelations(LearnerResult result) { - learnerSetupDAO.loadLazyRelations(result.getSetup()); - Hibernate.initialize(result.getSteps()); - result.getSteps().forEach(learnerResultStepDAO::loadLazyRelations); - } - - private void checkIfResultsCanBeDeleted(List results) { - final var learnerIsActive = results.stream() - .anyMatch(r -> r.getStatus().equals(LearnerResult.Status.IN_PROGRESS)); - - if (learnerIsActive) { - throw new ValidationException("Can't delete all LearnResults because the learner is active"); - } - } - - public void checkAccess(User user, Project project, LearnerResult learnerResult) { - projectDAO.checkAccess(user, project); - - if (learnerResult == null) { - throw new NotFoundException("The learner result could not be found."); - } - - if (!learnerResult.getProject().getId().equals(project.getId())) { - throw new UnauthorizedException("You are not allowed to access the learner result."); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/dao/LearnerResultStepDAO.java b/backend/src/main/java/de/learnlib/alex/learning/dao/LearnerResultStepDAO.java deleted file mode 100644 index c231ace4d..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/dao/LearnerResultStepDAO.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.dao; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.learning.entities.LearnerResultStep; -import de.learnlib.alex.learning.repositories.LearnerResultRepository; -import de.learnlib.alex.learning.repositories.LearnerResultStepRepository; -import org.apache.shiro.authz.UnauthorizedException; -import org.hibernate.Hibernate; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(rollbackFor = Exception.class) -public class LearnerResultStepDAO { - - private final ProjectDAO projectDAO; - private final LearnerResultDAO learnerResultDAO; - private final LearnerResultRepository learnerResultRepository; - private final LearnerResultStepRepository learnerResultStepRepository; - - public LearnerResultStepDAO( - ProjectDAO projectDAO, - @Lazy LearnerResultDAO learnerResultDAO, - LearnerResultRepository learnerResultRepository, - LearnerResultStepRepository learnerResultStepRepository - ) { - this.projectDAO = projectDAO; - this.learnerResultDAO = learnerResultDAO; - this.learnerResultStepRepository = learnerResultStepRepository; - this.learnerResultRepository = learnerResultRepository; - } - - public LearnerResultStep getById(User user, Long projectId, Long resultId, Long stepId) { - final var project = projectDAO.getByID(user, projectId); - final var result = learnerResultRepository.findById(resultId).orElse(null); - final var step = learnerResultStepRepository.getOne(stepId); - checkAccess(user, project, result, step); - loadLazyRelations(step); - return step; - } - - public LearnerResultStep update(Long stepId, LearnerResultStep step) { - final var stepToUpdate = learnerResultStepRepository.findById(stepId) - .orElseThrow(() -> new NotFoundException("The step could not be found.")); - - stepToUpdate.setStatistics(step.getStatistics()); - stepToUpdate.setCounterExample(step.getCounterExample()); - stepToUpdate.setState(step.getState()); - stepToUpdate.setAlgorithmInformation(step.getAlgorithmInformation()); - stepToUpdate.setErrorText(step.getErrorText()); - stepToUpdate.setEqOracle(step.getEqOracle()); - stepToUpdate.setModelCheckingResults(step.getModelCheckingResults()); - - final var updatedStep = learnerResultStepRepository.save(stepToUpdate); - loadLazyRelations(updatedStep); - - return updatedStep; - } - - public void loadLazyRelations(LearnerResultStep step) { - Hibernate.initialize(step.getModelCheckingResults()); - step.getModelCheckingResults().forEach(r -> Hibernate.initialize(r.getFormula())); - } - - private void checkAccess(User user, Project project, LearnerResult result, LearnerResultStep step) { - learnerResultDAO.checkAccess(user, project, result); - - if (step == null) { - throw new NotFoundException("The step could not be found."); - } - - if (!step.getResult().getId().equals(result.getId())) { - throw new UnauthorizedException("You are not allowed to access the learner step."); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/dao/LearnerSetupDAO.java b/backend/src/main/java/de/learnlib/alex/learning/dao/LearnerSetupDAO.java deleted file mode 100644 index 4b3976b48..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/dao/LearnerSetupDAO.java +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.dao; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.dao.ParameterizedSymbolDAO; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.dao.ProjectEnvironmentDAO; -import de.learnlib.alex.data.dao.SymbolDAO; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.repositories.ProjectEnvironmentRepository; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.learning.entities.LearnerSetup; -import de.learnlib.alex.learning.entities.LearnerStatus; -import de.learnlib.alex.learning.entities.LearningProcessStatus; -import de.learnlib.alex.learning.entities.WebDriverConfig; -import de.learnlib.alex.learning.repositories.LearnerResultRepository; -import de.learnlib.alex.learning.repositories.LearnerSetupRepository; -import de.learnlib.alex.learning.services.LearnerService; -import de.learnlib.alex.modelchecking.dao.ModelCheckingConfigDAO; -import de.learnlib.alex.modelchecking.entities.LtsFormulaSuite; -import de.learnlib.alex.modelchecking.repositories.LtsFormulaSuiteRepository; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import javax.persistence.EntityManager; -import javax.validation.ValidationException; -import org.hibernate.Hibernate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(rollbackFor = Exception.class) -public class LearnerSetupDAO { - - private final LearnerSetupRepository learnerSetupRepository; - private final ProjectRepository projectRepository; - private final ProjectDAO projectDAO; - private final ParameterizedSymbolDAO parameterizedSymbolDAO; - private final LearnerResultRepository learnerResultRepository; - private final ProjectEnvironmentRepository projectEnvironmentRepository; - private final EntityManager entityManager; - private final SymbolDAO symbolDAO; - private final LtsFormulaSuiteRepository ltsFormulaSuiteRepository; - private final ModelCheckingConfigDAO modelCheckingConfigDAO; - private final LearnerService learnerService; - - @Autowired - public LearnerSetupDAO(LearnerSetupRepository learnerSetupRepository, - ParameterizedSymbolDAO parameterizedSymbolDAO, - ProjectRepository projectRepository, - ProjectDAO projectDAO, - LearnerResultRepository learnerResultRepository, - ProjectEnvironmentRepository projectEnvironmentRepository, - EntityManager entityManager, - SymbolDAO symbolDAO, - LtsFormulaSuiteRepository ltsFormulaSuiteRepository, - ModelCheckingConfigDAO modelCheckingConfigDAO, - @Lazy LearnerService learnerService) { - this.learnerSetupRepository = learnerSetupRepository; - this.projectDAO = projectDAO; - this.projectRepository = projectRepository; - this.parameterizedSymbolDAO = parameterizedSymbolDAO; - this.learnerResultRepository = learnerResultRepository; - this.projectEnvironmentRepository = projectEnvironmentRepository; - this.entityManager = entityManager; - this.symbolDAO = symbolDAO; - this.ltsFormulaSuiteRepository = ltsFormulaSuiteRepository; - this.modelCheckingConfigDAO = modelCheckingConfigDAO; - this.learnerService = learnerService; - } - - public List getAll(User user, Long projectId) { - final Project project = projectRepository.findById(projectId).orElse(null); - projectDAO.checkAccess(user, project); - - final List setups = learnerSetupRepository.findAllByProject_Id(projectId); - setups.forEach(this::loadLazyRelations); - return setups; - } - - public LearnerSetup getById(User user, Long projectId, Long setupId) { - final Project project = projectRepository.findById(projectId).orElse(null); - final LearnerSetup setup = learnerSetupRepository.findById(setupId).orElse(null); - checkAccess(user, project, setup); - loadLazyRelations(setup); - return setup; - } - - public LearnerSetup removeSymbols(Long setupId, List symbols) { - final var setup = learnerSetupRepository.findById(setupId) - .orElseThrow(() -> new NotFoundException("setup not found.")); - - final var ids = symbols.stream() - .map(ParameterizedSymbol::getId) - .collect(Collectors.toList()); - - setup.getSymbols().removeIf(s -> ids.contains(s.getId())); - final var updatedSetup = learnerSetupRepository.save(setup); - - for (var ps : symbols) { - parameterizedSymbolDAO.delete(ps); - } - - loadLazyRelations(updatedSetup); - return updatedSetup; - } - - public LearnerSetup addSymbols(Long setupId, List symbols) { - final var setup = learnerSetupRepository.findById(setupId) - .orElseThrow(() -> new NotFoundException("setup not found.")); - - final var createdSymbols = symbols.stream() - .map(parameterizedSymbolDAO::create) - .collect(Collectors.toList()); - - setup.getSymbols().addAll(createdSymbols); - - final var updatedSetup = learnerSetupRepository.save(setup); - loadLazyRelations(updatedSetup); - return updatedSetup; - } - - public LearnerSetup update(User user, Long projectId, Long setupId, LearnerSetup setup) { - final Project project = projectRepository.findById(projectId).orElse(null); - final LearnerSetup setupInDb = learnerSetupRepository.findById(setupId).orElse(null); - checkAccess(user, project, setupInDb); - - setupInDb.setName(setup.getName()); - setupInDb.setAlgorithm(setup.getAlgorithm()); - setupInDb.setEquivalenceOracle(setup.getEquivalenceOracle()); - setupInDb.setEnableCache(setup.isEnableCache()); - - entityManager.detach(setup.getWebDriver()); - setup.getWebDriver().setId(null); - setupInDb.setWebDriver(setup.getWebDriver()); - - final var updatedModelCheckingConfig = modelCheckingConfigDAO.update(user, projectId, - setupInDb.getModelCheckingConfig().getId(), setup.getModelCheckingConfig()); - setupInDb.setModelCheckingConfig(updatedModelCheckingConfig); - - setupInDb.setEnvironments(projectEnvironmentRepository.findAllByIdIn(setup.getEnvironments().stream() - .map(ProjectEnvironment::getId) - .collect(Collectors.toList()))); - - setupInDb.setPreSymbol(setup.getPreSymbol().copy()); - setupInDb.setSymbols(setup.getSymbols().stream() - .collect(Collectors.groupingBy(ParameterizedSymbol::getAliasOrIdBasedName)) - .values() - .stream().map(l -> l.get(0)) - .map(ParameterizedSymbol::copy) - .collect(Collectors.toList())); - - if (setup.getPostSymbol() != null) { - setupInDb.setPostSymbol(setup.getPostSymbol().copy()); - } - - saveSymbols(setupInDb); - - final LearnerSetup updatedSetup = learnerSetupRepository.save(setupInDb); - loadLazyRelations(updatedSetup); - return updatedSetup; - } - - public LearnerSetup copy(User user, Long projectId, Long setupId, boolean saved) { - final Project project = projectRepository.findById(projectId).orElse(null); - final LearnerSetup setupInDb = learnerSetupRepository.findById(setupId).orElse(null); - checkAccess(user, project, setupInDb); - - final LearnerSetup newSetup = new LearnerSetup(); - newSetup.setProject(project); - newSetup.setName(setupInDb.getName()); - newSetup.setAlgorithm(setupInDb.getAlgorithm()); - newSetup.setEquivalenceOracle(setupInDb.getEquivalenceOracle()); - newSetup.setEnableCache(setupInDb.isEnableCache()); - newSetup.setSaved(saved); - - final WebDriverConfig webDriverConfig = setupInDb.getWebDriver(); - entityManager.detach(webDriverConfig); - webDriverConfig.setId(null); - - newSetup.setWebDriver(webDriverConfig); - newSetup.setEnvironments(projectEnvironmentRepository.findAllByIdIn(setupInDb.getEnvironments().stream() - .map(ProjectEnvironment::getId) - .collect(Collectors.toList()))); - - final var createdMCConfig = modelCheckingConfigDAO.create(user, projectId, setupInDb.getModelCheckingConfig()); - newSetup.setModelCheckingConfig(createdMCConfig); - - newSetup.setPreSymbol(setupInDb.getPreSymbol().copy()); - newSetup.setSymbols(setupInDb.getSymbols().stream() - .map(ParameterizedSymbol::copy) - .collect(Collectors.toList())); - newSetup.setPostSymbol(setupInDb.getPostSymbol() == null ? null : setupInDb.getPostSymbol().copy()); - - saveSymbols(newSetup); - - final LearnerSetup copiedSetup = learnerSetupRepository.save(newSetup); - loadLazyRelations(copiedSetup); - return copiedSetup; - } - - public List importLearnerSetups(User user, Project project, List setups, Map symbolRefMap) { - // symbol id -> symbol - final var symbolMap = symbolDAO.getAll(user, project.getId()).stream() - .collect(Collectors.toMap(s -> symbolRefMap != null ? symbolRefMap.get(s.getId()) : s.getId(), Function.identity())); - - // associate symbols - for (var setup : setups) { - setup.setProject(project); - - setup.setPreSymbol(importParameterizedSymbol(setup.getPreSymbol(), symbolMap)); - setup.setSymbols(setup.getSymbols().stream() - .map(ps -> importParameterizedSymbol(ps, symbolMap)) - .collect(Collectors.toList()) - ); - if (setup.getPostSymbol() != null) { - setup.setPostSymbol(importParameterizedSymbol(setup.getPostSymbol(), symbolMap)); - } - - setup.setEnvironments( - projectEnvironmentRepository.findByProject_IdAndNameIn(project.getId(), setup.getEnvironments().stream() - .map(ProjectEnvironment::getName) - .collect(Collectors.toList()) - ) - ); - - setup.getModelCheckingConfig().setFormulaSuites( - ltsFormulaSuiteRepository.findAllByProject_IdAndNameIn(project.getId(), setup.getModelCheckingConfig().getFormulaSuites().stream() - .map(LtsFormulaSuite::getName) - .collect(Collectors.toSet()) - ) - ); - - setup.setModelCheckingConfig(modelCheckingConfigDAO.create(user, project.getId(), setup.getModelCheckingConfig())); - } - - // save setups - final var importedSetups = learnerSetupRepository.saveAll(setups); - importedSetups.forEach(this::loadLazyRelations); - - return importedSetups; - } - - private ParameterizedSymbol importParameterizedSymbol(ParameterizedSymbol pSymbol, Map symbolMap) { - final var symbol = symbolMap.get(pSymbol.getSymbol().getId()); - pSymbol.setSymbol(symbol); - pSymbol.getParameterValues().forEach(pv -> { - final var param = symbol.findInputByNameAndType( - pv.getParameter().getName(), - pv.getParameter().getParameterType() - ); - pv.setParameter(param); - }); - pSymbol.getOutputMappings().forEach(om -> { - final var param = symbol.findOutputByNameAndType( - om.getParameter().getName(), - om.getParameter().getParameterType() - ); - om.setParameter(param); - }); - return parameterizedSymbolDAO.create(pSymbol); - } - - public LearnerSetup create(User user, Long projectId, LearnerSetup setup) { - final var project = projectRepository.findById(projectId).orElse(null); - projectDAO.checkAccess(user, project); - - if (!setup.getSymbols().stream() - .peek(ps -> { - ps.setSymbol(symbolDAO.get(user, project, ps.getSymbol().getId())); - }) - .collect(Collectors.groupingBy(ParameterizedSymbol::getAliasOrComputedName)) - .values().stream() - .map(l -> l.size() == 1) - .reduce(Boolean.TRUE, (a, b) -> a && b)) { - throw new IllegalArgumentException("The list of symbols may not contain duplicates"); - } - - saveSymbols(setup); - - setup.setProject(project); - setup.setId(null); - setup.getWebDriver().setId(null); - - final var mcConfig = modelCheckingConfigDAO.create(user, projectId, setup.getModelCheckingConfig()); - setup.setModelCheckingConfig(mcConfig); - - final LearnerSetup createdSetup = learnerSetupRepository.save(setup); - loadLazyRelations(createdSetup); - - return createdSetup; - } - - public void delete(User user, Long projectId, Long setupId) { - final var project = projectRepository.findById(projectId).orElse(null); - final var setup = learnerSetupRepository.findById(setupId).orElse(null); - checkAccess(user, project, setup); - - if (learnerResultRepository.countAllBySetup_Id(setupId) > 0) { - throw new ValidationException("The setup cannot be deleted because it is referenced by a learner result."); - } else { - learnerSetupRepository.delete(setup); - } - } - - public List getActiveLearnerSetups(User user, Long projectId) { - LearnerStatus status = learnerService.getStatus(user, projectId); - if (status.isActive()) { - List currentProcessSingletonList = Optional.ofNullable(status.getCurrentProcess()) - .map(LearningProcessStatus::getResult) - .map(List::of) - .orElse(Collections.emptyList()); - - return Stream.of(currentProcessSingletonList, status.getQueue()) - .flatMap(List::stream) - .map(LearnerResult::getSetup) - .collect(Collectors.toList()); - } - return Collections.emptyList(); - } - - public void checkAccess(User user, Project project, LearnerSetup learnerSetup) { - projectDAO.checkAccess(user, project); - - if (learnerSetup == null) { - throw new NotFoundException("The learner setup could not be found."); - } - - if (!learnerSetup.getProjectId().equals(project.getId())) { - throw new NotFoundException("Cannot access the learner setup."); - } - } - - public void loadLazyRelations(LearnerSetup learnerSetup) { - Hibernate.initialize(learnerSetup.getPreSymbol()); - ParameterizedSymbolDAO.loadLazyRelations(learnerSetup.getPreSymbol()); - - Hibernate.initialize(learnerSetup.getSymbols()); - learnerSetup.getSymbols().forEach(ParameterizedSymbolDAO::loadLazyRelations); - - if (learnerSetup.getPostSymbol() != null) { - Hibernate.initialize(learnerSetup.getPostSymbol()); - ParameterizedSymbolDAO.loadLazyRelations(learnerSetup.getPostSymbol()); - } - - Hibernate.initialize(learnerSetup.getEnvironments()); - learnerSetup.getEnvironments().forEach(ProjectEnvironmentDAO::loadLazyRelations); - - Hibernate.initialize(learnerSetup.getWebDriver()); - modelCheckingConfigDAO.loadLazyRelations(learnerSetup.getModelCheckingConfig()); - } - - private void saveSymbols(LearnerSetup setup) { - setup.getPreSymbol().setId(null); - parameterizedSymbolDAO.create(setup.getPreSymbol()); - for (ParameterizedSymbol ps : setup.getSymbols()) { - ps.setId(null); - parameterizedSymbolDAO.create(ps); - } - if (setup.getPostSymbol() != null) { - setup.getPostSymbol().setId(null); - parameterizedSymbolDAO.create(setup.getPostSymbol()); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/DifferenceTreeInput.java b/backend/src/main/java/de/learnlib/alex/learning/entities/DifferenceTreeInput.java deleted file mode 100644 index 49f1f957f..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/DifferenceTreeInput.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities; - -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.learning.entities.learnlibproxies.CompactMealyMachineProxy; - -import javax.validation.constraints.NotNull; - -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") -@JsonSubTypes({ - @JsonSubTypes.Type(name = "automata", value = DifferenceTreeInput.AutomataInput.class), - @JsonSubTypes.Type(name = "learnerResults", value = DifferenceTreeInput.LearnerResultInput.class), -}) -public abstract class DifferenceTreeInput { - - @NotNull - public DifferenceTreeStrategy strategy; - - @JsonTypeName("automata") - public static class AutomataInput extends DifferenceTreeInput { - - @NotNull - public CompactMealyMachineProxy automaton1; - - @NotNull - public CompactMealyMachineProxy automaton2; - } - - @JsonTypeName("learnerResults") - public static class LearnerResultInput extends DifferenceTreeInput { - - @NotNull - public Long result1; - - @NotNull - public Integer step1; - - @NotNull - public Long result2; - - @NotNull - public Integer step2; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/DifferenceTreeStrategy.java b/backend/src/main/java/de/learnlib/alex/learning/entities/DifferenceTreeStrategy.java deleted file mode 100644 index d30a6a495..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/DifferenceTreeStrategy.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities; - -public enum DifferenceTreeStrategy { - DISCRIMINATION_TREE, - W_METHOD, - WP_METHOD -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerOptions.java b/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerOptions.java deleted file mode 100644 index dbaa43e7e..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerOptions.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities; - -import de.learnlib.alex.webhooks.entities.Webhook; - -/** Options to pass to the learning process. */ -public class LearnerOptions { - - /** The comment to pass to the learner result. **/ - private String comment; - - private Webhook webhook; - - public String getComment() { - return comment; - } - - public void setComment(String comment) { - this.comment = comment; - } - - public Webhook getWebhook() { - return webhook; - } - - public void setWebhook(Webhook webhook) { - this.webhook = webhook; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerResult.java b/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerResult.java deleted file mode 100644 index 635882212..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerResult.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.entities.Project; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; -import javax.persistence.OrderBy; -import javax.persistence.Transient; - -/** - * Entity class to store the result of a test run, i.e. the outcome of a learn iteration and must not be the final - * result. The result contains the configuration of the learning process, the resulting hypothesis and some meta data - * (duration, #EQ, ...). - */ -@Entity -@JsonPropertyOrder(alphabetic = true) -public class LearnerResult implements Serializable { - - private static final long serialVersionUID = 4619722174562257862L; - - public enum Status { - PENDING, - IN_PROGRESS, - FINISHED, - ABORTED, - FAILED - } - - /** The id of the LearnerResult in the DB. */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - /** The reference to the Project the test run belongs to. */ - @ManyToOne(optional = false, fetch = FetchType.EAGER) - @JsonIgnore - private Project project; - - /** The test no. within a Project which lead to the result. */ - @Column(nullable = false) - private Long testNo; - - /** The setup that has been used for the learning process. */ - @OneToOne(cascade = CascadeType.REMOVE) - private LearnerSetup setup; - - /** The steps of the LearnerResult. */ - @OneToMany( - mappedBy = "result", - cascade = {CascadeType.REMOVE}, - orphanRemoval = true - ) - @OrderBy("stepNo ASC") - private List steps; - - /** A comment to describe the intention / setting of the learn process. This field is optional. */ - private String comment; - - /** The current status. */ - private Status status; - - /** The user who started the learn process. */ - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "executedById") - private User executedBy; - - private String errorMessage; - - /** Constructor. */ - public LearnerResult() { - this.steps = new ArrayList<>(); - this.comment = ""; - this.status = Status.PENDING; - this.errorMessage = ""; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Project getProject() { - return project; - } - - public void setProject(Project project) { - this.project = project; - } - - @Transient - @JsonProperty("project") - public Long getProjectId() { - return project == null ? null : project.getId(); - } - - @JsonProperty("project") - public void setProjectId(Long projectId) { - this.project = new Project(projectId); - } - - public Long getTestNo() { - return testNo; - } - - public void setTestNo(Long testNo) { - this.testNo = testNo; - } - - public List getSteps() { - return steps; - } - - public void setSteps(List steps) { - this.steps = steps; - } - - public String getComment() { - return comment; - } - - public void setComment(String comment) { - this.comment = comment; - } - - public LearnerSetup getSetup() { - return setup; - } - - public void setSetup(LearnerSetup setup) { - this.setup = setup; - } - - public String getErrorMessage() { - return errorMessage; - } - - public void setErrorMessage(String errorMessage) { - this.errorMessage = errorMessage; - } - - /** - * Get the statistic of this learn step. - * - * @return The learning statistics. - */ - @JsonProperty - @Transient - public Statistics getStatistics() { - final Statistics statistics = new Statistics(); - steps.forEach(s -> statistics.updateBy(s.getStatistics())); - if (!steps.isEmpty()) { - statistics.setStartDate(steps.get(0).getStatistics().getStartDate()); - } - return statistics; - } - - public void setStatistics(Statistics statistics) { - } - - /** - * Did some kind of error occurred during the learning, i.e. the error text property is set. - * - * @return true if the result represents a failed learning process; null otherwise. - */ - @Transient - @JsonProperty("error") - public Boolean isError() { - return steps.stream().anyMatch(s -> s.getErrorText() != null); - } - - public Status getStatus() { - return status; - } - - public void setStatus(Status status) { - this.status = status; - } - - @JsonProperty("executedBy") - public User getExecutedBy() { - return executedBy; - } - - @JsonIgnore - public void setExecutedBy(User executedBy) { - this.executedBy = executedBy; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - LearnerResult result = (LearnerResult) o; - return Objects.equals(id, result.id); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } - - @Override - public String toString() { - return "[LearnerResult " + id + "] " + project + " / " + testNo; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerResultStep.java b/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerResultStep.java deleted file mode 100644 index 72f02c520..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerResultStep.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import de.learnlib.alex.learning.entities.learnlibproxies.CompactMealyMachineProxy; -import de.learnlib.alex.learning.entities.learnlibproxies.DefaultQueryProxy; -import de.learnlib.alex.learning.entities.learnlibproxies.eqproxies.AbstractEquivalenceOracleProxy; -import de.learnlib.alex.modelchecking.entities.ModelCheckingResult; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Transient; -import javax.persistence.UniqueConstraint; - -/** - * Entity class to store the result of a test run, i.e. the outcome of a learn iteration and must not be the final - * result. The result contains the configuration of the learning process, the resulting hypothesis and some meta data - * (duration, #EQ, ...). - */ -@Entity -@Table( - uniqueConstraints = @UniqueConstraint(columnNames = {"result_id", "stepNo"}) -) -@JsonPropertyOrder(alphabetic = true) -public class LearnerResultStep implements Serializable { - - private static final long serialVersionUID = -6932946318109366918L; - - /** The id of the LearnerResult in the DB. */ - private Long id; - - /** The result the step is part of. */ - private LearnerResult result; - - /** The step no. within a test run which lead to the result. */ - private Long stepNo; - - /** The type of EQ oracle to find a counter example. */ - private AbstractEquivalenceOracleProxy eqOracle; - - /** The hypothesis of the result. */ - private CompactMealyMachineProxy hypothesis; - - /** The statistics of the result. */ - private Statistics statistics; - - /** The last found counterexample. */ - private DefaultQueryProxy counterExample; - - /** This is an optional property and can contain things like the internal data structure. */ - private String algorithmInformation; - - /** The internal state of the learner. */ - private byte[] state; - - /** - * If this field is set some sort of error occurred during the learning. In this case this field stores more - * information about the error. All other field can still have data, that are valid to some extent and should only - * be used carefully. - */ - private String errorText; - - private List modelCheckingResults; - - /** - * Default constructor. - */ - public LearnerResultStep() { - this.statistics = new Statistics(); - this.modelCheckingResults = new ArrayList<>(); - } - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - @ManyToOne(fetch = FetchType.EAGER, optional = false) - @JoinColumn(name = "result_id") - public LearnerResult getResult() { - return result; - } - - @JsonProperty("result") - @Transient - public Long getResultId() { - return this.result == null ? null : this.result.getId(); - } - - @JsonProperty("result") - @Transient - public void setResultId(Long resultId) { - this.result = new LearnerResult(); - this.result.setId(resultId); - } - - public void setResult(LearnerResult result) { - this.result = result; - } - - @Column(nullable = false) - public Long getStepNo() { - return stepNo; - } - - public void setStepNo(Long stepNo) { - this.stepNo = stepNo; - } - - @Column(columnDefinition = "BYTEA") - public AbstractEquivalenceOracleProxy getEqOracle() { - return eqOracle; - } - - public void setEqOracle(AbstractEquivalenceOracleProxy eqOracle) { - this.eqOracle = eqOracle; - } - - @Embedded - @JsonProperty("hypothesis") - public CompactMealyMachineProxy getHypothesis() { - return hypothesis; - } - - @JsonProperty("hypothesis") - public void setHypothesis(CompactMealyMachineProxy hypothesis) { - this.hypothesis = hypothesis; - } - - @Embedded - public Statistics getStatistics() { - return statistics; - } - - public void setStatistics(Statistics statistics) { - this.statistics = statistics; - } - - @Embedded - public DefaultQueryProxy getCounterExample() { - return counterExample; - } - - public void setCounterExample(DefaultQueryProxy counterExample) { - this.counterExample = counterExample; - } - - @Column(columnDefinition = "TEXT") - public String getAlgorithmInformation() { - return algorithmInformation; - } - - public void setAlgorithmInformation(String algorithmInformation) { - this.algorithmInformation = algorithmInformation; - } - - @Column - @JsonProperty("errorText") - public String getErrorText() { - return errorText; - } - - @Transient - @JsonProperty("error") - public boolean isError() { - return errorText != null; - } - - @Column(columnDefinition = "BYTEA") - @JsonIgnore - public byte[] getState() { - return state; - } - - @JsonIgnore - public void setState(byte[] state) { - this.state = state; - } - - public void setErrorText(String errorText) { - this.errorText = errorText; - } - - @OneToMany( - cascade = CascadeType.REMOVE, - orphanRemoval = true - ) - public List getModelCheckingResults() { - return modelCheckingResults; - } - - public void setModelCheckingResults(List modelCheckingResults) { - this.modelCheckingResults = modelCheckingResults; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - LearnerResultStep step = (LearnerResultStep) o; - return Objects.equals(id, step.id); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } - - @Override - public String toString() { - Long testNo = 0L; - if (result != null) { - testNo = result.getTestNo(); - } - - return "[LearnerResultStep " + this.id + "] " + result + " / " + testNo + " / " + stepNo + ": " + hypothesis; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerResumeConfiguration.java b/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerResumeConfiguration.java deleted file mode 100644 index dbf185f5f..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerResumeConfiguration.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.learning.entities.learnlibproxies.eqproxies.AbstractEquivalenceOracleProxy; -import de.learnlib.alex.learning.entities.learnlibproxies.eqproxies.SampleEQOracleProxy; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; - -/** - * Entity to hold the information needed to resume a learning process. - */ -public class LearnerResumeConfiguration { - - /** The type of EQ oracle to find a counter example. */ - @NotNull - protected AbstractEquivalenceOracleProxy eqOracle; - - /** The step number from where to continue. */ - @NotNull - @Min(0) - private int stepNo; - - /** The ids of the symbols to add. */ - private List symbolsToAdd; - - /** Constructor. */ - public LearnerResumeConfiguration() { - super(); - this.symbolsToAdd = new ArrayList<>(); - } - - public void checkConfiguration() throws IllegalArgumentException { - // one should be able to continue learning if the sample eq oracle is used without - // having specified a counterexample if a new symbol is added. - if (eqOracle == null) { - throw new IllegalArgumentException("Could not find an EQ oracle."); - } - - if (eqOracle instanceof SampleEQOracleProxy) { - try { - eqOracle.checkParameters(); - } catch (IllegalArgumentException e) { // counterexamples are empty - if (symbolsToAdd.isEmpty()) { - throw new IllegalArgumentException("You haven't specified neither a counterexample nor a symbol to add."); - } - } - } else { - eqOracle.checkParameters(); - } - - if (stepNo <= 0) { - throw new IllegalArgumentException("The step number may not be less than 1"); - } - } - - public int getStepNo() { - return stepNo; - } - - public void setStepNo(int stepNo) { - this.stepNo = stepNo; - } - - public AbstractEquivalenceOracleProxy getEqOracle() { - return eqOracle; - } - - public void setEqOracle(AbstractEquivalenceOracleProxy eqOracle) { - this.eqOracle = eqOracle; - } - - public List getSymbolsToAdd() { - return symbolsToAdd; - } - - public void setSymbolsToAdd(List symbolsToAdd) { - this.symbolsToAdd = symbolsToAdd; - } - - @JsonIgnore - public List getSymbolIds() { - return symbolsToAdd.stream() - .map(ps -> ps.getSymbol().getId()) - .collect(Collectors.toList()); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerSetup.java b/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerSetup.java deleted file mode 100644 index 9db1345e0..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerSetup.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.learning.entities.algorithms.AbstractLearningAlgorithm; -import de.learnlib.alex.learning.entities.learnlibproxies.eqproxies.AbstractEquivalenceOracleProxy; -import de.learnlib.alex.modelchecking.entities.ModelCheckingConfig; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.OneToOne; -import javax.persistence.Transient; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import org.hibernate.annotations.Cascade; -import org.hibernate.annotations.CascadeType; - -@Entity -public class LearnerSetup implements Serializable { - - private static final long serialVersionUID = 4839405295048332641L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @ManyToOne(optional = false) - private Project project; - - private String name; - - private boolean enableCache; - - private boolean saved; - - @Cascade(CascadeType.ALL) - private AbstractLearningAlgorithm algorithm; - - @ManyToMany - @NotEmpty - private List environments; - - @ManyToMany(cascade = javax.persistence.CascadeType.REMOVE) - @NotEmpty - private List symbols; - - @ManyToOne(optional = false, cascade = javax.persistence.CascadeType.REMOVE) - @NotNull - private ParameterizedSymbol preSymbol; - - @ManyToOne(cascade = javax.persistence.CascadeType.REMOVE) - private ParameterizedSymbol postSymbol; - - @NotNull - @Column(columnDefinition = "BYTEA") - private AbstractEquivalenceOracleProxy equivalenceOracle; - - @NotNull - @OneToOne(cascade = javax.persistence.CascadeType.ALL) - private WebDriverConfig webDriver; - - @NotNull - @OneToOne(cascade = javax.persistence.CascadeType.ALL) - private ModelCheckingConfig modelCheckingConfig; - - public LearnerSetup() { - this.environments = new ArrayList<>(); - this.symbols = new ArrayList<>(); - this.enableCache = false; - this.saved = false; - this.modelCheckingConfig = new ModelCheckingConfig(); - } - - @Transient - @JsonIgnore - public List getSigma() { - return symbols.stream() - .map(ParameterizedSymbol::getAliasOrComputedName) - .collect(Collectors.toList()); - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Project getProject() { - return project; - } - - public void setProject(Project project) { - this.project = project; - } - - @JsonProperty("project") - public Long getProjectId() { - return project.getId(); - } - - @JsonProperty("project") - public void setProjectId(Long projectId) { - this.project = new Project(); - this.project.setId(projectId); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name == null || name.trim().equals("") ? "" : name; - } - - public boolean isEnableCache() { - return enableCache; - } - - public void setEnableCache(boolean enableCache) { - this.enableCache = enableCache; - } - - public AbstractLearningAlgorithm getAlgorithm() { - return algorithm; - } - - public void setAlgorithm(AbstractLearningAlgorithm algorithm) { - this.algorithm = algorithm; - } - - public List getEnvironments() { - return environments; - } - - public void setEnvironments(List environments) { - this.environments = environments; - } - - public List getSymbols() { - return symbols; - } - - public void setSymbols(List symbols) { - this.symbols = symbols; - } - - public ParameterizedSymbol getPreSymbol() { - return preSymbol; - } - - public void setPreSymbol(ParameterizedSymbol preSymbol) { - this.preSymbol = preSymbol; - } - - public ParameterizedSymbol getPostSymbol() { - return postSymbol; - } - - public void setPostSymbol(ParameterizedSymbol postSymbol) { - this.postSymbol = postSymbol; - } - - public AbstractEquivalenceOracleProxy getEquivalenceOracle() { - return equivalenceOracle; - } - - public void setEquivalenceOracle(AbstractEquivalenceOracleProxy equivalenceOracle) { - this.equivalenceOracle = equivalenceOracle; - } - - public WebDriverConfig getWebDriver() { - return webDriver; - } - - public void setWebDriver(WebDriverConfig webDriver) { - this.webDriver = webDriver; - } - - public boolean isSaved() { - return saved; - } - - public void setSaved(boolean saved) { - this.saved = saved; - } - - public ModelCheckingConfig getModelCheckingConfig() { - return modelCheckingConfig; - } - - public void setModelCheckingConfig(ModelCheckingConfig modelCheckingConfig) { - this.modelCheckingConfig = modelCheckingConfig; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerStartConfiguration.java b/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerStartConfiguration.java deleted file mode 100644 index d63d9b008..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerStartConfiguration.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities; - -public class LearnerStartConfiguration { - - /** Options for the learning process. */ - private LearnerOptions options; - - /** The setup to execute. */ - private LearnerSetup setup; - - public LearnerStartConfiguration() { - this.options = new LearnerOptions(); - } - - public LearnerOptions getOptions() { - return options; - } - - public void setOptions(LearnerOptions options) { - this.options = options == null ? new LearnerOptions() : options; - } - - public LearnerSetup getSetup() { - return setup; - } - - public void setSetup(LearnerSetup setup) { - this.setup = setup; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerStatus.java b/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerStatus.java deleted file mode 100644 index 5ca9cba7e..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/LearnerStatus.java +++ /dev/null @@ -1,41 +0,0 @@ -package de.learnlib.alex.learning.entities; - -import java.util.ArrayList; -import java.util.List; -import javax.persistence.Transient; - -public class LearnerStatus { - - private LearningProcessStatus currentProcess; - - private List queue; - - public LearnerStatus() { - this.queue = new ArrayList<>(); - } - - public LearnerStatus(LearningProcessStatus currentProcess) { - this.currentProcess = currentProcess; - } - - public LearningProcessStatus getCurrentProcess() { - return currentProcess; - } - - public void setCurrentProcess(LearningProcessStatus currentProcess) { - this.currentProcess = currentProcess; - } - - public List getQueue() { - return queue; - } - - public void setQueue(List queue) { - this.queue = queue; - } - - @Transient - public boolean isActive() { - return currentProcess != null || !queue.isEmpty(); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/LearningProcessStatus.java b/backend/src/main/java/de/learnlib/alex/learning/entities/LearningProcessStatus.java deleted file mode 100644 index ac4e7bd72..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/LearningProcessStatus.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities; - -import de.learnlib.alex.learning.entities.learnlibproxies.DefaultQueryProxy; -import de.learnlib.alex.learning.services.LearnerService; -import java.util.List; - -public class LearningProcessStatus { - private LearnerResult result; - private LearnerService.LearnerPhase phase; - private List currentQueries; - private Long currentQueryCount = 0L; - private Long currentSymbolCount = 0L; - - public LearnerResult getResult() { - return result; - } - - public void setResult(LearnerResult result) { - this.result = result; - } - - public LearnerService.LearnerPhase getPhase() { - return phase; - } - - public void setPhase(LearnerService.LearnerPhase phase) { - this.phase = phase; - } - - public List getCurrentQueries() { - return currentQueries; - } - - public void setCurrentQueries(List currentQueries) { - this.currentQueries = currentQueries; - } - - public Long getCurrentQueryCount() { - return currentQueryCount; - } - - public void setCurrentQueryCount(Long currentQueryCount) { - this.currentQueryCount = currentQueryCount; - } - - public Long getCurrentSymbolCount() { - return currentSymbolCount; - } - - public void setCurrentSymbolCount(Long currentSymbolCount) { - this.currentSymbolCount = currentSymbolCount; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/ModelExportFormat.java b/backend/src/main/java/de/learnlib/alex/learning/entities/ModelExportFormat.java deleted file mode 100644 index a051f767f..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/ModelExportFormat.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities; - -public enum ModelExportFormat { - DOT -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/ReadOutputConfig.java b/backend/src/main/java/de/learnlib/alex/learning/entities/ReadOutputConfig.java deleted file mode 100644 index 75fc02264..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/ReadOutputConfig.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities; - -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import java.util.ArrayList; -import java.util.List; - -/** - * Helper object that is used to test words. - */ -public class ReadOutputConfig { - - private ParameterizedSymbol preSymbol; - private List symbols = new ArrayList<>(); - private ParameterizedSymbol postSymbol; - private WebDriverConfig driverConfig; - - public ReadOutputConfig() { - } - - public ReadOutputConfig(ParameterizedSymbol preSymbol, - List symbols, - ParameterizedSymbol postSymbol, - WebDriverConfig driverConfig) { - this.preSymbol = preSymbol; - this.symbols = symbols; - this.postSymbol = postSymbol; - this.driverConfig = driverConfig; - } - - public WebDriverConfig getDriverConfig() { - return driverConfig; - } - - public void setDriverConfig(WebDriverConfig driverConfig) { - this.driverConfig = driverConfig; - } - - public ParameterizedSymbol getPreSymbol() { - return preSymbol; - } - - public void setPreSymbol(ParameterizedSymbol preSymbol) { - this.preSymbol = preSymbol; - } - - public List getSymbols() { - return symbols; - } - - public void setSymbols(List symbols) { - this.symbols = symbols; - } - - public ParameterizedSymbol getPostSymbol() { - return postSymbol; - } - - public void setPostSymbol(ParameterizedSymbol postSymbol) { - this.postSymbol = postSymbol; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/SeparatingWord.java b/backend/src/main/java/de/learnlib/alex/learning/entities/SeparatingWord.java deleted file mode 100644 index fa2268d97..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/SeparatingWord.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities; - -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.List; -import java.util.Objects; -import net.automatalib.words.Word; - -/** Helper class for the output difference of two hypotheses. */ -public class SeparatingWord { - - /** The input. */ - private final Word input; - - /** The The output of the first hypothesis. */ - private final Word output1; - - /** The output of the second hypothesis. */ - private final Word output2; - - /** Constructor. */ - public SeparatingWord() { - this(Word.epsilon(), Word.epsilon(), Word.epsilon()); - } - - /** - * Constructor. - * - * @param input - * The input. - * @param output1 - * The output of the first hypothesis. - * @param output2 - * The output of the second hypothesis. - */ - public SeparatingWord(Word input, Word output1, Word output2) { - this.input = input; - this.output1 = output1; - this.output2 = output2; - } - - public Word getInput() { - return input; - } - - public Word getOutput1() { - return output1; - } - - public Word getOutput2() { - return output2; - } - - @JsonProperty("input") - public List getInputList() { - return input.asList(); - } - - @JsonProperty("output1") - public List getOutput1List() { - return output1.asList(); - } - - @JsonProperty("output2") - public List getOutput2List() { - return output2.asList(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof SeparatingWord)) { - return false; - } - SeparatingWord that = (SeparatingWord) o; - return Objects.equals(getInput(), that.getInput()) - && Objects.equals(getOutput1(), that.getOutput1()) - && Objects.equals(getOutput2(), that.getOutput2()); - } - - @Override - public int hashCode() { - return Objects.hash(getInput(), getOutput1(), getOutput2()); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/Statistics.java b/backend/src/main/java/de/learnlib/alex/learning/entities/Statistics.java deleted file mode 100644 index 3227f9e19..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/Statistics.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import de.learnlib.alex.common.Constants; -import java.io.Serializable; -import java.time.ZonedDateTime; -import java.util.Objects; -import javax.persistence.AttributeOverride; -import javax.persistence.AttributeOverrides; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.persistence.Embedded; -import javax.persistence.Transient; - -/** Embeddable statistics object that contains statistics related to a learning experiment. */ -@Embeddable -@JsonPropertyOrder(alphabetic = true) -public class Statistics implements Serializable { - - private static final long serialVersionUID = -5221139436025380739L; - - /** Sub Statistics class to store information by Learner and EqOracle. */ - @Embeddable - public static class DetailedStatistics implements Serializable { - - private static final long serialVersionUID = -2601019208764457063L; - - /** Data of the Learner. */ - private long learner; - - /** Data of the EqOracle. */ - private long eqOracle; - - public DetailedStatistics() { - this(0L, 0L); - } - - public DetailedStatistics(long learner, long eqOracle) { - this.learner = learner; - this.eqOracle = eqOracle; - } - - /** - * @return The total data, i.e. Learner data + EqOracle data. - */ - @Transient - @JsonProperty("total") - public long getTotal() { - return learner + eqOracle; - } - - @JsonProperty("learner") - public long getLearner() { - return learner; - } - - public void setLearner(long learner) { - this.learner = learner; - } - - @JsonProperty("eqOracle") - public long getEqOracle() { - return eqOracle; - } - - public void setEqOracle(long eqOracle) { - this.eqOracle = eqOracle; - } - - /** - * Increment the values of the Learner and EqOracle data by another DetailedStatistics. - * - * @param offset - * A DetailedStatistics with the values to add. - */ - public void updateBy(DetailedStatistics offset) { - this.learner += offset.learner; - this.eqOracle += offset.eqOracle; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - DetailedStatistics that = (DetailedStatistics) o; - return learner == that.learner && eqOracle == that.eqOracle; - } - - @Override - public int hashCode() { - return Objects.hash(learner, eqOracle); - } - } - - /** - * Date and Time when the learning step was started. - * The format is conform with the ISO 8601 (JavaScript-Style). - */ - @JsonIgnore - private ZonedDateTime startDate; - - /** The amount of equivalence queries. */ - private long eqsUsed; - - /** The duration of the learn step. */ - private DetailedStatistics duration; - - /** The amount of membership queries/ SUL resets. */ - private DetailedStatistics mqsUsed; - - /** The amount of actual symbols called during the learning process. */ - private DetailedStatistics symbolsUsed; - - /** - * Default constructor. - */ - public Statistics() { - this.startDate = ZonedDateTime.now(); - this.eqsUsed = 0L; - this.duration = new DetailedStatistics(); - this.mqsUsed = new DetailedStatistics(); - this.symbolsUsed = new DetailedStatistics(); - } - - /** - * Update the statistics by given values. - * - * @param statistics - * The statistics whose values should be used to update the statistics. - */ - public void updateBy(Statistics statistics) { - eqsUsed += statistics.eqsUsed; - duration.updateBy(statistics.duration); - mqsUsed.updateBy(statistics.mqsUsed); - symbolsUsed.updateBy(statistics.symbolsUsed); - } - - @JsonIgnore - public ZonedDateTime getStartDate() { - return startDate; - } - - @JsonIgnore - public void setStartDate(ZonedDateTime startDate) { - this.startDate = startDate; - } - - @Transient - @JsonProperty("startDate") - public String getStartDateAsString() { - return startDate.format(Constants.DATE_TIME_FORMATTER); - } - - @JsonProperty("startDate") - public void setStartDateByString(String dateAsString) { - this.startDate = ZonedDateTime.parse(dateAsString); - } - - public long getEqsUsed() { - return eqsUsed; - } - - public void setEqsUsed(long eqsUsed) { - this.eqsUsed = eqsUsed; - } - - @Embedded - @AttributeOverrides({ - @AttributeOverride(name = "learner", column = @Column(name = "duration_learner")), - @AttributeOverride(name = "eqOracle", column = @Column(name = "duration_eqOracle")) - }) - public DetailedStatistics getDuration() { - return duration; - } - - public void setDuration(DetailedStatistics duration) { - this.duration = duration; - } - - @Embedded - @AttributeOverrides({ - @AttributeOverride(name = "learner", column = @Column(name = "mqs_learner")), - @AttributeOverride(name = "eqOracle", column = @Column(name = "mqs_eqOracle")) - }) - public DetailedStatistics getMqsUsed() { - return mqsUsed; - } - - public void setMqsUsed(DetailedStatistics mqsUsed) { - this.mqsUsed = mqsUsed; - } - - @Embedded - @AttributeOverrides({ - @AttributeOverride(name = "learner", column = @Column(name = "symbolsUsed_learner")), - @AttributeOverride(name = "eqOracle", column = @Column(name = "symbolsUsed_eqOracle")) - }) - public DetailedStatistics getSymbolsUsed() { - return symbolsUsed; - } - - public void setSymbolsUsed(DetailedStatistics symbolsUsed) { - this.symbolsUsed = symbolsUsed; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/TestSuiteGenerationConfig.java b/backend/src/main/java/de/learnlib/alex/learning/entities/TestSuiteGenerationConfig.java deleted file mode 100644 index c7710d951..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/TestSuiteGenerationConfig.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities; - -import javax.validation.constraints.Min; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - -/** The configuration class for the test suite generation. */ -public class TestSuiteGenerationConfig { - - /** Which strategy is used for test generation. */ - public enum GenerationMethod { - DT, - W_METHOD, - WP_METHOD, - TRANS_COVER, - } - - /** The number of the step. */ - @NotNull - @Min(1) - private Long stepNo; - - /** The name of the generated test suite. */ - @NotEmpty - private String name; - - /** The ID of the test suite to update. */ - private Long testSuiteToUpdateId; - - /** which method is used. */ - @NotNull - private GenerationMethod method; - - /** Constructor. */ - public TestSuiteGenerationConfig() { - this.stepNo = 1L; - this.name = "test suite"; - this.method = GenerationMethod.DT; - } - - public Long getStepNo() { - return stepNo; - } - - public void setStepNo(Long stepNo) { - this.stepNo = stepNo; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public GenerationMethod getMethod() { - return method; - } - - public void setMethod(GenerationMethod method) { - this.method = method; - } - - public Long getTestSuiteToUpdateId() { - return testSuiteToUpdateId; - } - - public void setTestSuiteToUpdateId(Long testSuiteToUpdateId) { - this.testSuiteToUpdateId = testSuiteToUpdateId; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/WebDriverConfig.java b/backend/src/main/java/de/learnlib/alex/learning/entities/WebDriverConfig.java deleted file mode 100644 index 86144b608..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/WebDriverConfig.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import java.io.Serializable; -import java.net.URL; -import java.time.Duration; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -import org.openqa.selenium.Dimension; -import org.openqa.selenium.Platform; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.chrome.ChromeOptions; -import org.openqa.selenium.edge.EdgeOptions; -import org.openqa.selenium.firefox.FirefoxOptions; -import org.openqa.selenium.remote.AbstractDriverOptions; -import org.openqa.selenium.remote.LocalFileDetector; -import org.openqa.selenium.remote.RemoteWebDriver; -import org.openqa.selenium.safari.SafariOptions; - -/** - * The abstract web driver configuration class. - */ -@Entity -public class WebDriverConfig implements Serializable { - - private static final long serialVersionUID = -2663686839180427383L; - - /** The selenium implicit wait time. */ - private static final int DEFAULT_IMPLICITLY_WAIT = 0; - - /** How long should be waited for the page to load before a timeout. */ - private static final int DEFAULT_PAGE_LOAD_TIMEOUT = 10; - - /** How long should be waited for JavaScript to execute before a timeout. */ - private static final int DEFAULT_SCRIPT_TIMEOUT = 10; - - /** The id of the config in the database. */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @JsonIgnore - private Long id; - - /** The width of the browser window. */ - @Min(value = 0) - private int width; - - /** The height of the browser window. */ - @Min(value = 0) - private int height; - - /** The implicit wait time for selenium. */ - private int implicitlyWait; - - /** The page load timeout time for selenium. */ - private int pageLoadTimeout; - - /** The script timeout time for selenium. */ - private int scriptTimeout; - - /** The target platform. */ - @NotNull - private Platform platform; - - /** The browser to run the tests in. */ - @NotBlank - private String browser; - - /** The browser version. */ - @NotNull - private String version; - - /** - * Constructor. - */ - public WebDriverConfig() { - this.width = 0; - this.height = 0; - this.implicitlyWait = DEFAULT_IMPLICITLY_WAIT; - this.pageLoadTimeout = DEFAULT_PAGE_LOAD_TIMEOUT; - this.scriptTimeout = DEFAULT_SCRIPT_TIMEOUT; - this.version = ""; - this.platform = Platform.ANY; - } - - /** - * Creates a new instance of a web driver. - * - * @return The new web driver. - * @throws Exception - * If the instantiation of the web driver fails. - */ - public WebDriver createWebDriver() throws Exception { - final URL remoteURL = new URL(System.getProperty("webdriver.remote.url")); - - final AbstractDriverOptions options; - - switch (browser) { - case "chrome" -> { - options = new ChromeOptions(); - } - case "firefox" -> { - options = new FirefoxOptions(); - } - case "msedge" -> options = new EdgeOptions(); - case "safari" -> options = new SafariOptions(); - default -> throw new IllegalArgumentException("Invalid browser specified"); - } - - options.setPlatformName(platform.toString()); - options.setAcceptInsecureCerts(true); - - if (!version.trim().equals("")) { - options.setBrowserVersion(version); - } - - final var driver = new RemoteWebDriver(remoteURL, options); - driver.setFileDetector(new LocalFileDetector()); - manage(driver); - return driver; - } - - /** - * Handle timeouts and browser dimensions. - * - * @param driver - * The web driver. - */ - protected void manage(final WebDriver driver) { - driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(pageLoadTimeout)); - driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(scriptTimeout)); - - if (implicitlyWait > 0) { - driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(implicitlyWait)); - } - - if (height > 0 && width > 0) { - driver.manage().window().setSize(new Dimension(width, height)); - } - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public int getWidth() { - return width; - } - - public void setWidth(int width) { - this.width = Math.max(width, 0); - } - - public int getHeight() { - return height; - } - - public void setHeight(int height) { - this.height = Math.max(height, 0); - } - - public int getImplicitlyWait() { - return implicitlyWait; - } - - public void setImplicitlyWait(int implicitlyWait) { - this.implicitlyWait = Math.max(implicitlyWait, 0); - } - - public int getPageLoadTimeout() { - return pageLoadTimeout; - } - - public void setPageLoadTimeout(int pageLoadTimeout) { - this.pageLoadTimeout = Math.max(pageLoadTimeout, 0); - } - - public int getScriptTimeout() { - return scriptTimeout; - } - - public void setScriptTimeout(int scriptTimeout) { - this.scriptTimeout = Math.max(scriptTimeout, 0); - } - - public Platform getPlatform() { - return platform; - } - - public void setPlatform(Platform platform) { - this.platform = platform; - } - - public String getBrowser() { - return browser; - } - - public void setBrowser(String browser) { - this.browser = browser; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/algorithms/AbstractLearningAlgorithm.java b/backend/src/main/java/de/learnlib/alex/learning/entities/algorithms/AbstractLearningAlgorithm.java deleted file mode 100644 index d77e50299..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/algorithms/AbstractLearningAlgorithm.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.algorithms; - -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import de.learnlib.api.Resumable; -import de.learnlib.api.algorithm.LearningAlgorithm; -import de.learnlib.api.oracle.MembershipOracle; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; - -/** - * Parent class of all algorithms. - * - * @param - * The input type. - * @param - * The output type. - */ -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "name") -@JsonSubTypes({ - @JsonSubTypes.Type(name = "DHC", value = DHC.class), - @JsonSubTypes.Type(name = "DT", value = DiscriminationTree.class), - @JsonSubTypes.Type(name = "KEARNS_VAZIRANI", value = KearnsVazirani.class), - @JsonSubTypes.Type(name = "LSTAR", value = LStar.class), - @JsonSubTypes.Type(name = "TTT", value = TTT.class) -}) -public abstract class AbstractLearningAlgorithm implements Serializable { - - private static final long serialVersionUID = 670184782484991650L; - - /** - * Creates a new learner. - * - * @param alphabet - * The input alphabet. - * @param oracle - * The membership oracle. - * @return An instance of the learner. - */ - public abstract LearningAlgorithm.MealyLearner createLearner(Alphabet alphabet, - MembershipOracle> oracle); - - /** - * Get the internal data structures as string representation. - * - * @param learner - * The learner - * @return The internal data structures. - */ - public abstract String getInternalData(LearningAlgorithm.MealyLearner learner); - - /** - * Set the learner to a previous state. - * - * @param learner - * The learner. - * @param data - * The serialized learner state. - * @throws IOException - * If something with the input streams goes wrong. - * @throws ClassNotFoundException - * If the class of the serialized learner state cannot be found. - */ - public abstract void resume(LearningAlgorithm.MealyLearner learner, byte[] data) - throws IOException, ClassNotFoundException; - - /** - * Get the serialized learner state. - * - * @param learner - * The learner to suspend. - * @return The serialized state. - * @throws IOException - * If something with the output streams goes wrong. - */ - public byte[] suspend(LearningAlgorithm.MealyLearner learner) throws IOException { - if (learner instanceof Resumable) { - final ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); - try (final ObjectOutputStream objectOut = new ObjectOutputStream(byteOut)) { - objectOut.writeObject(((Resumable) learner).suspend()); - objectOut.flush(); - return byteOut.toByteArray(); - } - } else { - return new byte[0]; - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/algorithms/DHC.java b/backend/src/main/java/de/learnlib/alex/learning/entities/algorithms/DHC.java deleted file mode 100644 index c75c9df43..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/algorithms/DHC.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.algorithms; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.algorithms.dhc.mealy.MealyDHC; -import de.learnlib.algorithms.dhc.mealy.MealyDHCBuilder; -import de.learnlib.algorithms.dhc.mealy.MealyDHCState; -import de.learnlib.api.algorithm.LearningAlgorithm; -import de.learnlib.api.oracle.MembershipOracle; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.Serializable; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; - -/** - * Class that provides the LearnLib implementation of the DHC algorithm for ALEX. - */ -@JsonTypeName("DHC") -public class DHC extends AbstractLearningAlgorithm implements Serializable { - - private static final long serialVersionUID = -1703212406344298512L; - - @Override - public LearningAlgorithm.MealyLearner createLearner(Alphabet sigma, - MembershipOracle> oracle) { - return new MealyDHCBuilder() - .withAlphabet(sigma) - .withOracle(oracle) - .create(); - } - - @Override - public String getInternalData(LearningAlgorithm.MealyLearner learner) { - return ""; - } - - @Override - public void resume(LearningAlgorithm.MealyLearner learner, byte[] data) - throws IOException, ClassNotFoundException { - try (final ObjectInputStream objectIn = new ObjectInputStream(new ByteArrayInputStream(data))) { - final MealyDHCState state = (MealyDHCState) objectIn.readObject(); - ((MealyDHC) learner).resume(state); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/algorithms/DiscriminationTree.java b/backend/src/main/java/de/learnlib/alex/learning/entities/algorithms/DiscriminationTree.java deleted file mode 100644 index 219082e39..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/algorithms/DiscriminationTree.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.algorithms; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.algorithms.discriminationtree.DTLearnerState; -import de.learnlib.algorithms.discriminationtree.hypothesis.HState; -import de.learnlib.algorithms.discriminationtree.mealy.DTLearnerMealy; -import de.learnlib.algorithms.discriminationtree.mealy.DTLearnerMealyBuilder; -import de.learnlib.api.algorithm.LearningAlgorithm; -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDTNode; -import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDiscriminationTree; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.Serializable; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; - -/** - * Class that provides the LearnLib implementation of the Discrimination Tree algorithm for ALEX. - */ -@JsonTypeName("DT") -public class DiscriminationTree extends AbstractLearningAlgorithm implements Serializable { - - private static final long serialVersionUID = 2655022507456200915L; - - @Override - public LearningAlgorithm.MealyLearner createLearner(Alphabet sigma, - MembershipOracle> oracle) { - return new DTLearnerMealyBuilder() - .withAlphabet(sigma) - .withOracle(oracle) - .create(); - } - - @Override - public String getInternalData(LearningAlgorithm.MealyLearner learner) { - if (!(learner instanceof DTLearnerMealy)) { - throw new IllegalArgumentException("Can not read the internal data because the algorithm types" - + "were different"); - } - - return toJSON(((DTLearnerMealy) learner).getDiscriminationTree()); - } - - @Override - public void resume(LearningAlgorithm.MealyLearner learner, byte[] data) - throws IOException, ClassNotFoundException { - try (final ObjectInputStream objectIn = new ObjectInputStream(new ByteArrayInputStream(data))) { - final DTLearnerState, Void, String> state = - (DTLearnerState, Void, String>) objectIn.readObject(); - ((DTLearnerMealy) learner).resume(state); - } - } - - /** - * Serializes the discrimination tree of the discrimination tree algorithm into JSON. - * - * @param dtree - * The tree to convert into nice JSON. - * @return The JSON string of the given tree. - */ - private String toJSON(AbstractWordBasedDiscriminationTree, HState, Void, String>> dtree) { - return toJSON(dtree.getRoot()); - } - - private String toJSON(AbstractWordBasedDTNode, HState, Void, String>> node) { - StringBuilder result = new StringBuilder(); - result.append('{'); - - if (node.getParentOutcome() != null) { - result.append("\"edgeLabel\": \""); - result.append(node.getParentOutcome()); - result.append("\","); - } - - if (node.isLeaf()) { - result.append("\"data\": \""); - result.append(node.getData()); - result.append('"'); - } else { - result.append("\"discriminator\": \""); - result.append(node.getDiscriminator()); - result.append("\", "); - - result.append("\"children\": ["); - node.getChildEntries().forEach(entry -> { - AbstractWordBasedDTNode child = entry.getValue(); - result.append(toJSON(child)); - result.append(","); - }); - - // remove last ',' - if (result.charAt(result.length() - 1) == ',') { - result.setLength(result.length() - 1); - } - - result.append(']'); - } - - result.append('}'); - return result.toString(); - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/algorithms/KearnsVazirani.java b/backend/src/main/java/de/learnlib/alex/learning/entities/algorithms/KearnsVazirani.java deleted file mode 100644 index 2aa2961f0..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/algorithms/KearnsVazirani.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.algorithms; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.algorithms.kv.mealy.KearnsVaziraniMealy; -import de.learnlib.algorithms.kv.mealy.KearnsVaziraniMealyBuilder; -import de.learnlib.algorithms.kv.mealy.KearnsVaziraniMealyState; -import de.learnlib.api.algorithm.LearningAlgorithm; -import de.learnlib.api.oracle.MembershipOracle; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.Serializable; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; - -/** - * Class that provides the LearnLib implementation of the Kearns Vazirani algorithm for ALEX. - */ -@JsonTypeName("KEARNS_VAZIRANI") -public class KearnsVazirani extends AbstractLearningAlgorithm implements Serializable { - - private static final long serialVersionUID = 4571297392539122947L; - - @Override - public LearningAlgorithm.MealyLearner createLearner(Alphabet alphabet, - MembershipOracle> membershipOracle) { - return new KearnsVaziraniMealyBuilder() - .withAlphabet(alphabet) - .withOracle(membershipOracle) - .create(); - } - - @Override - public String getInternalData(LearningAlgorithm.MealyLearner mealyLearner) { - return ""; - } - - @Override - public void resume(LearningAlgorithm.MealyLearner learner, byte[] data) - throws IOException, ClassNotFoundException { - try (final ObjectInputStream objectIn = new ObjectInputStream(new ByteArrayInputStream(data))) { - final KearnsVaziraniMealyState state = - (KearnsVaziraniMealyState) objectIn.readObject(); - ((KearnsVaziraniMealy) learner).resume(state); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/algorithms/LStar.java b/backend/src/main/java/de/learnlib/alex/learning/entities/algorithms/LStar.java deleted file mode 100644 index 9224b6063..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/algorithms/LStar.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.algorithms; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.algorithms.lstar.AutomatonLStarState; -import de.learnlib.algorithms.lstar.mealy.ExtensibleLStarMealy; -import de.learnlib.algorithms.lstar.mealy.ExtensibleLStarMealyBuilder; -import de.learnlib.api.algorithm.LearningAlgorithm; -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.datastructure.observationtable.ObservationTable; -import de.learnlib.datastructure.observationtable.writer.ObservationTableASCIIWriter; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.Serializable; -import net.automatalib.automata.transducers.impl.compact.CompactMealy; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; - -/** - * Class that provides the LearnLib implementation of the extended L* algorithm for ALEX. - */ -@JsonTypeName("LSTAR") -public class LStar extends AbstractLearningAlgorithm implements Serializable { - - private static final long serialVersionUID = -4916532996322906039L; - - @Override - public LearningAlgorithm.MealyLearner createLearner(Alphabet sigma, - MembershipOracle> oracle) { - return new ExtensibleLStarMealyBuilder() - .withAlphabet(sigma) - .withOracle(oracle) - .create(); - } - - @Override - public String getInternalData(LearningAlgorithm.MealyLearner learner) { - if (!(learner instanceof ExtensibleLStarMealy)) { - throw new IllegalArgumentException("Can not read the internal data because the algorithm types" - + "were different"); - } - - ObservationTable observationTable = ((ExtensibleLStarMealy) learner).getObservationTable(); - StringBuilder observationTableAsString = new StringBuilder(); - new ObservationTableASCIIWriter().write(observationTable, observationTableAsString); - return observationTableAsString.toString(); - } - - @Override - public void resume(LearningAlgorithm.MealyLearner learner, byte[] data) - throws IOException, ClassNotFoundException { - try (final ObjectInputStream objectIn = new ObjectInputStream(new ByteArrayInputStream(data))) { - final AutomatonLStarState, CompactMealy, Integer> state = - (AutomatonLStarState, CompactMealy, Integer>) objectIn.readObject(); - ((ExtensibleLStarMealy) learner).resume(state); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/algorithms/TTT.java b/backend/src/main/java/de/learnlib/alex/learning/entities/algorithms/TTT.java deleted file mode 100644 index 16facace6..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/algorithms/TTT.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.algorithms; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.algorithms.ttt.base.AbstractBaseDTNode; -import de.learnlib.algorithms.ttt.base.BaseTTTDiscriminationTree; -import de.learnlib.algorithms.ttt.base.TTTLearnerState; -import de.learnlib.algorithms.ttt.mealy.TTTLearnerMealy; -import de.learnlib.algorithms.ttt.mealy.TTTLearnerMealyBuilder; -import de.learnlib.api.algorithm.LearningAlgorithm; -import de.learnlib.api.oracle.MembershipOracle; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.Serializable; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; - -/** - * Class that provides the LearnLib implementation of the TTT algorithm for ALEX. - */ -@JsonTypeName("TTT") -public class TTT extends AbstractLearningAlgorithm implements Serializable { - - private static final long serialVersionUID = -7594934697689034183L; - - @Override - public LearningAlgorithm.MealyLearner createLearner(Alphabet sigma, - MembershipOracle> oracle) { - return new TTTLearnerMealyBuilder() - .withAlphabet(sigma) - .withOracle(oracle) - .create(); - } - - @Override - public String getInternalData(LearningAlgorithm.MealyLearner learner) { - if (!(learner instanceof TTTLearnerMealy)) { - throw new IllegalArgumentException("Can not read the internal data because the algorithm types" - + "were different"); - } - - TTTLearnerMealy tttLearner = (TTTLearnerMealy) learner; - return toJSON(tttLearner.getDiscriminationTree()); - } - - @Override - public void resume(LearningAlgorithm.MealyLearner learner, byte[] data) - throws IOException, ClassNotFoundException { - try (final ObjectInputStream objectIn = new ObjectInputStream(new ByteArrayInputStream(data))) { - final TTTLearnerState> state = - (TTTLearnerState>) objectIn.readObject(); - ((TTTLearnerMealy) learner).resume(state); - } - } - - /** - * Serializes the discrimination tree of the TTT algorithm into JSON. - * - * @param dtree - * The tree to convert into nice JSON. - * @return The JSON string of the given tree. - */ - private String toJSON(BaseTTTDiscriminationTree> dtree) { - return toJSON(dtree.getRoot()); - } - - private String toJSON(AbstractBaseDTNode> node) { - StringBuilder result = new StringBuilder(); - result.append('{'); - - if (node.getParentOutcome() != null) { - result.append("\"edgeLabel\": \""); - result.append(node.getParentOutcome()); - result.append("\","); - } - - if (node.isLeaf()) { - result.append("\"data\": \""); - result.append(node.getData()); - result.append('"'); - } else { - result.append("\"discriminator\": \""); - result.append(node.getDiscriminator()); - result.append("\", "); - - result.append("\"children\": ["); - node.getChildEntries().forEach(entry -> { - AbstractBaseDTNode> child = entry.getValue(); - result.append(toJSON(child)); - result.append(","); - }); - - // remove last ',' - if (result.charAt(result.length() - 1) == ',') { - result.setLength(result.length() - 1); - } - - result.append(']'); - } - - result.append('}'); - return result.toString(); - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/export/LearnerSetupExportableEntity.java b/backend/src/main/java/de/learnlib/alex/learning/entities/export/LearnerSetupExportableEntity.java deleted file mode 100644 index eff580ff6..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/export/LearnerSetupExportableEntity.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.export; - -import com.fasterxml.jackson.databind.JsonNode; -import de.learnlib.alex.data.entities.export.ExportableEntity; - -public class LearnerSetupExportableEntity extends ExportableEntity { - - private JsonNode learnerSetups; - - public LearnerSetupExportableEntity(String version, JsonNode learnerSetups) { - super(version, "learnerSetups"); - this.learnerSetups = learnerSetups; - } - - public JsonNode getLearnerSetups() { - return learnerSetups; - } - - public void setLearnerSetups(JsonNode learnerSetups) { - this.learnerSetups = learnerSetups; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/CompactMealyMachineProxy.java b/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/CompactMealyMachineProxy.java deleted file mode 100644 index 9fcee395e..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/CompactMealyMachineProxy.java +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.learnlibproxies; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.type.CollectionType; -import java.io.IOException; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.persistence.Transient; -import net.automatalib.automata.concepts.StateIDs; -import net.automatalib.automata.transducers.MealyMachine; -import net.automatalib.automata.transducers.impl.compact.CompactMealy; -import net.automatalib.words.Alphabet; -import net.automatalib.words.impl.GrowingMapAlphabet; - -/** - * Proxy around a {@link net.automatalib.automata.transducers.impl.compact.CompactMealy} from the LearnLib. - * The Proxy is needed to make it easier to (de-)serialize the MealyMachine into/ from JSON. - */ -@Embeddable -public class CompactMealyMachineProxy implements Serializable { - - private static final long serialVersionUID = -5155147869595906457L; - - /** Create one static ObjectMapper to (de-)serialize the Proxy for the DB. */ - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - - /** The states of the machine. */ - private List nodes; - - /** The initial state. */ - private Integer initNode; - - /** The transitions between the states. */ - private List edges; - - /** - * Create a proxy around a specific MealyMachine. - * - * @param machine - * The MealyMachine the Proxy should wrap in - * @param alphabet - * The alphabet of the MealyMachine. - * @return A new Proxy around the given MealyMachine. - */ - public static CompactMealyMachineProxy createFrom(MealyMachine machine, - Alphabet alphabet) { - return createProxy(machine, alphabet); - } - - private static CompactMealyMachineProxy createProxy(MealyMachine machine, - Alphabet alphabet) { - final StateIDs stateIDs = machine.stateIDs(); - - final Integer initialStateId = stateIDs.getStateId(machine.getInitialState()); - final List stateIds = machine.getStates().stream() - .map(stateIDs::getStateId) - .collect(Collectors.toList()); - - final List transitionProxies = new ArrayList<>(); - machine.getStates().forEach(state -> - alphabet.forEach(sym -> { - final T trans = machine.getTransition(state, sym); - if (trans != null) { - final CompactMealyTransitionProxy transProxy = new CompactMealyTransitionProxy(); - transProxy.setInput(sym); - transProxy.setOutput(machine.getTransitionOutput(trans)); - transProxy.setFrom(stateIDs.getStateId(state)); - transProxy.setTo(stateIDs.getStateId(machine.getSuccessor(state, sym))); - transitionProxies.add(transProxy); - } - }) - ); - - final CompactMealyMachineProxy proxy = new CompactMealyMachineProxy(); - proxy.setInitNode(initialStateId); - proxy.setNodes(stateIds); - proxy.setEdges(transitionProxies); - - return proxy; - } - - /** - * Get the states of the mealy machine as a list. - * - * @return The stats of the mealy machine. - */ - @Transient - public List getNodes() { - return nodes; - } - - /** - * Set new states for the mealy machine. - * - * @param nodes - * The new states. - */ - public void setNodes(List nodes) { - this.nodes = nodes; - } - - /** - * Getter method to interact with the DB, because the Java standard serialization doesn't work. - * - * @return The Nodes of the machine as JSON string. - */ - @Column(name = "nodes") - @JsonIgnore - public String getNodesDB() { - try { - return OBJECT_MAPPER.writeValueAsString(nodes); - } catch (JsonProcessingException e) { - e.printStackTrace(); - return ""; - } - } - - /** - * Setter method to interact with the DB, because the Java standard deserialization doesn't work. - * - * @param nodesAsString - * The Nodes of the machine as JSON string. - */ - @JsonIgnore - public void setNodesDB(String nodesAsString) { - try { - CollectionType valueType = OBJECT_MAPPER.getTypeFactory() - .constructCollectionType(List.class, Integer.class); - this.nodes = OBJECT_MAPPER.readValue(nodesAsString, valueType); - } catch (IOException e) { - e.printStackTrace(); - } - } - - /** - * Get the initial state of the mealy machine. - * - * @return The initial state. - */ - public Integer getInitNode() { - return initNode; - } - - /** - * Declare a state as the initial state. - * - * @param initNode - * The new initial state. - */ - public void setInitNode(Integer initNode) { - this.initNode = initNode; - } - - /** - * Get all the transition/ edges of the mealy machine, i.e. the connections between the states. - * - * @return The transition of the mealy machine as List of MealyTransitionProxies. - */ - @Transient - public List getEdges() { - return edges; - } - - /** - * Set the list of transition of the mealy machine new. - * - * @param edges - * The new transition/ edges. - */ - public void setEdges(List edges) { - this.edges = edges; - } - - /** - * Getter method to interact with the DB, because the Java standard serialization doesn't work. - * - * @return The Edges of the machine as JSON string. - */ - @Column(name = "edges", columnDefinition = "TEXT") - @JsonIgnore - public String getEdgesDB() { - try { - return OBJECT_MAPPER.writeValueAsString(edges); - } catch (JsonProcessingException e) { - e.printStackTrace(); - return ""; - } - } - - /** - * Setter method to interact with the DB, because the Java standard deserialization doesn't work. - * - * @param edgesAsString - * The Edges of the machine as JSON string. - */ - @JsonIgnore - public void setEdgesDB(String edgesAsString) { - try { - CollectionType valueType = OBJECT_MAPPER.getTypeFactory() - .constructCollectionType(List.class, - CompactMealyTransitionProxy.class); - this.edges = OBJECT_MAPPER.readValue(edgesAsString, valueType); - } catch (IOException e) { - e.printStackTrace(); - } - } - - /** - * Create an Alphabet based on the proxy. - * - * @return An Alphabet with all the proxy input symbols. - */ - @Transient - @JsonIgnore - public Alphabet createAlphabet() { - final Set inputs = edges.stream() - .map(CompactMealyTransitionProxy::getInput) - .collect(Collectors.toSet()); - - return new GrowingMapAlphabet<>(inputs); - } - - /** - * Create a CompactMealy based on the Proxy. - * - * @param sigma - * The alphabet to use. - * @return A new CompactMealy based on the Proxy. - */ - public CompactMealy createMealyMachine(Alphabet sigma) { - CompactMealy machine = new CompactMealy<>(sigma); - addStatesTo(machine); - addEdgesTo(machine); - return machine; - } - - private void addStatesTo(CompactMealy machine) { - for (int i = 0; i < nodes.size(); i++) { - machine.addState(); - } - machine.setInitialState(initNode); - } - - private void addEdgesTo(CompactMealy machine) { - for (CompactMealyTransitionProxy t : edges) { - machine.addTransition(t.getFrom(), t.getInput(), t.getTo(), t.getOutput()); - } - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/CompactMealyTransitionProxy.java b/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/CompactMealyTransitionProxy.java deleted file mode 100644 index 4da4bd0c0..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/CompactMealyTransitionProxy.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.learnlibproxies; - -import java.io.Serializable; - -/** - * Proxy around a {@link net.automatalib.automata.transducers.impl.compact.CompactMealyTransition} - * The Proxy is needed to make it easier to (de-)serialize the Transition into/ from JSON. - */ -public class CompactMealyTransitionProxy implements Serializable { - - private static final long serialVersionUID = -5676454094797505993L; - - /** The number of the state on which the transition starts. */ - private int from; - - /** The input that triggers the transition. */ - private String input; - - /** The number of the state on which the transition ends. */ - private int to; - - /** The output that happens during the transition. */ - private String output; - - /** - * Get the number of the state this transition starts. - * - * @return The start state of the transition. - */ - public int getFrom() { - return from; - } - - /** - * Set a new start state for the transition. - * - * @param from - * The new start state. - */ - public void setFrom(int from) { - this.from = from; - } - - /** - * Get the input that triggers the transition. - * - * @return The input that will cause the transition. - */ - public String getInput() { - return input; - } - - /** - * Set a new input that will trigger the transition. - * - * @param input - * The new input to trigger the transition. - */ - public void setInput(String input) { - this.input = input; - } - - /** - * Get the number of the state the transition ends. - * - * @return The end state of the transition. - */ - public int getTo() { - return to; - } - - /** - * Set a new end state for the transition. - * - * @param to - * The new end state. - */ - public void setTo(int to) { - this.to = to; - } - - /** - * Get the output that happens during the transition. - * - * @return The output of the transition. - */ - public String getOutput() { - return output; - } - - /** - * Set a new output for the transition. - * - * @param output - * The output that happens during the transition. - */ - public void setOutput(String output) { - this.output = output; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/DefaultQueryProxy.java b/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/DefaultQueryProxy.java deleted file mode 100644 index 980600bd8..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/DefaultQueryProxy.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.learnlibproxies; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.api.query.DefaultQuery; -import java.io.IOException; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.persistence.OrderBy; -import javax.persistence.Transient; -import net.automatalib.words.Word; - -/** - * Proxy around a {@link DefaultQuery}. - * The Proxy is needed to make it easier to (de-)serialize the Transition into/ from JSON. - */ -@Embeddable -public class DefaultQueryProxy implements Serializable { - - private static final long serialVersionUID = 4759682392322006213L; - - /** Create one static ObjectMapper to (de-)serialize the Proxy for the DB. */ - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - - /** The Prefix of the query as Strings. */ - @OrderBy - private List prefix; - - /** The Suffix of the query as Strings. */ - @OrderBy - private List suffix; - - /** The Output of the query as Strings. */ - @OrderBy - private List output; - - /** - * Default constructor that creates a new list for the prefix, the suffix and the output. - */ - public DefaultQueryProxy() { - this.prefix = new ArrayList<>(); - this.suffix = new ArrayList<>(); - this.output = new ArrayList<>(); - } - - /** - * Create a new Proxy based on the provided DefaultQuery. - * - * @param query - * The base Query of the new proxy. Can be null. - * @return The new Proxy around the DefaultQuery.. - */ - public static DefaultQueryProxy createFrom(DefaultQuery> query) { - DefaultQueryProxy newProxy = new DefaultQueryProxy(); - if (query != null) { - newProxy.prefix = query.getPrefix().asList(); - newProxy.suffix = query.getSuffix().asList(); - if (query.getOutput() != null) { - newProxy.output = query.getOutput().asList(); - } - } - - return newProxy; - } - - @Transient - @JsonProperty - public List getPrefix() { - return prefix; - } - - public void setPrefix(List prefix) { - this.prefix = prefix; - } - - @Transient - @JsonProperty - public List getSuffix() { - return suffix; - } - - public void setSuffix(List suffix) { - this.suffix = suffix; - } - - @Transient - @JsonProperty - public List getOutput() { - return output; - } - - public void setOutput(List output) { - this.output = output; - } - - /** - * Getter method to interact with the DB, because the Java standard serialization doesn't work. - * - * @return The Proxy as JSON string. - */ - @Column(name = "counterExample", columnDefinition = "TEXT") - @JsonIgnore - public String getProxyDB() { - try { - return OBJECT_MAPPER.writeValueAsString(this); - } catch (JsonProcessingException e) { - e.printStackTrace(); - return "{}"; - } - } - - /** - * Setter method to interact with the DB, because the Java standard deserialization doesn't work. - * - * @param proxyAsString - * The Proxy as JSON string. - */ - @JsonIgnore - public void setProxyDB(String proxyAsString) { - try { - DefaultQueryProxy that = OBJECT_MAPPER.readValue(proxyAsString, DefaultQueryProxy.class); - this.prefix = that.prefix; - this.suffix = that.suffix; - this.output = that.output; - } catch (IOException e) { - e.printStackTrace(); - } - } - - /** - * Create a DefaultQuery based on this proxy. - * - * @return The new DefaultQuery. - */ - public DefaultQuery> createDefaultQuery() { - Word prefixAsWord = Word.fromList(prefix); - Word suffixAsWord = Word.fromList(suffix); - Word outputAsWord = Word.fromList(output); - return new DefaultQuery<>(prefixAsWord, suffixAsWord, outputAsWord); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - DefaultQueryProxy that = (DefaultQueryProxy) o; - return Objects.equals(prefix, that.prefix) - && Objects.equals(suffix, that.suffix) - && Objects.equals(output, that.output); - } - - @Override - public int hashCode() { - return Objects.hash(prefix, suffix, output); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/AbstractEquivalenceOracleProxy.java b/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/AbstractEquivalenceOracleProxy.java deleted file mode 100644 index 9dd3467cf..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/AbstractEquivalenceOracleProxy.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.learnlibproxies.eqproxies; - -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import de.learnlib.api.oracle.EquivalenceOracle; -import de.learnlib.api.oracle.MembershipOracle; -import java.io.Serializable; -import net.automatalib.automata.transducers.MealyMachine; -import net.automatalib.words.Word; - -/** - * Base class for Proxies around a the different EquivalenceOracles from the LearnLib. The Proxy is needed to make it - * easier to (de-)serialize the EQ oracles into/ from JSON. - */ -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") -@JsonSubTypes({ - @JsonSubTypes.Type(name = "fuzzy_state_cover", value = FuzzyStateCoverEQOracleProxy.class), - @JsonSubTypes.Type(name = "random_word", value = MealyRandomWordsEQOracleProxy.class), - @JsonSubTypes.Type(name = "complete", value = CompleteExplorationEQOracleProxy.class), - @JsonSubTypes.Type(name = "sample", value = SampleEQOracleProxy.class), - @JsonSubTypes.Type(name = "wmethod", value = WMethodEQOracleProxy.class), - @JsonSubTypes.Type(name = "hypothesis", value = HypothesisEQOracleProxy.class), - @JsonSubTypes.Type(name = "test_suite", value = TestSuiteEQOracleProxy.class), - @JsonSubTypes.Type(name = "wp_method", value = WpMethodEQOracleProxy.class) -}) -public abstract class AbstractEquivalenceOracleProxy implements Serializable { - - private static final long serialVersionUID = 6270462192160289890L; - - /** How many membership queries are in a batch by default. */ - private static final int DEFAULT_BATCH_SIZE = 20; - - /** How many membership queries are posed together. */ - protected int batchSize; - - /** Constructor. */ - public AbstractEquivalenceOracleProxy() { - this.batchSize = DEFAULT_BATCH_SIZE; - } - - /** - * Check if the parameter of the proxy are valid, i.e. it is possible to create a functional EQ oracle out of the - * proxy. If everything is OK nothing will happen. If there are errors an exception will be thrown. This exception - * should have a clear error message. - * - * @throws IllegalArgumentException - * If the parameters are wrong. - */ - public abstract void checkParameters() throws IllegalArgumentException; - - /** - * Create a EQ oracle connected with a MQ oracle based on this proxy. - * - * @param membershipOracle - * The MQ oracle to test against a hypothesis. - * @return An EquivalenceOracle from the LearnLib based on the proxy. - */ - public abstract EquivalenceOracle, String, Word> createEqOracle( - MembershipOracle> membershipOracle); - - public int getBatchSize() { - return batchSize; - } - - public void setBatchSize(Integer batchSize) { - this.batchSize = (batchSize == null || batchSize < 1) ? DEFAULT_BATCH_SIZE : batchSize; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/CompleteExplorationEQOracleProxy.java b/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/CompleteExplorationEQOracleProxy.java deleted file mode 100644 index 86f078517..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/CompleteExplorationEQOracleProxy.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.learnlibproxies.eqproxies; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.api.oracle.EquivalenceOracle; -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.oracle.equivalence.CompleteExplorationEQOracle; -import java.io.Serializable; -import net.automatalib.automata.transducers.MealyMachine; -import net.automatalib.words.Word; - -/** - * Proxy around a {@link CompleteExplorationEQOracle}. - * The Proxy is needed to make it easier to (de-)serialize the Transition into/ from JSON. - */ -@JsonTypeName("complete") -public class CompleteExplorationEQOracleProxy extends AbstractEquivalenceOracleProxy implements Serializable { - - private static final long serialVersionUID = 8363769818889990904L; - - /** The minimal depth to explore, i.e. minimal length of words to test. */ - private int minDepth; - - /** The maximal depth to explore, i.e. minimal length of words to test. */ - private int maxDepth; - - /** - * Default constructor. - */ - public CompleteExplorationEQOracleProxy() { - this.minDepth = 1; - this.maxDepth = 1; - } - - /** - * Constructor that initialises all fields. - * - * @param minDepth - * The minimal depth to explore. - * @param maxDepth - * The maximal depth to explore. - */ - public CompleteExplorationEQOracleProxy(int minDepth, int maxDepth) { - this.minDepth = minDepth; - this.maxDepth = maxDepth; - } - - /** - * Get the minimal depth to explore, i.e. the minimal length of the words to test. - * - * @return The minimal depth to explore. - */ - public int getMinDepth() { - return minDepth; - } - - /** - * Set a new minimum for the exploration level. - * - * @param minDepth - * The new minimal depth to explore. - */ - public void setMinDepth(int minDepth) { - this.minDepth = minDepth; - } - - /** - * Get the maximal depth to explore, i.e. the maximal length of the words to test. - * - * @return The maximal depth to explore. - */ - public int getMaxDepth() { - return maxDepth; - } - - /** - * Set a new maximum for the exploration level. - * - * @param maxDepth - * The new maximal depth to explore. - */ - public void setMaxDepth(int maxDepth) { - this.maxDepth = maxDepth; - } - - @Override - public void checkParameters() throws IllegalArgumentException { - if (minDepth < 0 || maxDepth < 0) { - throw new IllegalArgumentException("Complete EQ Oracle: min depth and max depth must not be negative."); - } else if (minDepth > maxDepth) { - throw new IllegalArgumentException("Complete EQ Oracle: max depth must be greater or equal to min depth."); - } - } - - @Override - public EquivalenceOracle, String, Word> createEqOracle( - MembershipOracle> membershipOracle) { - return new CompleteExplorationEQOracle<>(membershipOracle, minDepth, maxDepth, batchSize); - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/FuzzyStateCoverEQOracleProxy.java b/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/FuzzyStateCoverEQOracleProxy.java deleted file mode 100644 index e48e19d36..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/FuzzyStateCoverEQOracleProxy.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.learnlibproxies.eqproxies; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.learning.services.oracles.FuzzyStateCoverEQOracle; -import de.learnlib.api.oracle.EquivalenceOracle; -import de.learnlib.api.oracle.MembershipOracle; -import java.util.Random; -import net.automatalib.automata.transducers.MealyMachine; -import net.automatalib.words.Word; - -@JsonTypeName("fuzzy_state_cover") -public class FuzzyStateCoverEQOracleProxy extends AbstractEquivalenceOracleProxy { - - /** The seed to use for the RNG. */ - public static final int RANDOM_SEED = 42; - - /** The minimal length of the random generated words. */ - private int minLength; - - /** The maximal length of the random generated words. */ - private int maxLength; - - /** The seed to use for the random number generator. */ - private int seed; - - /** How many words should be created before ending the oracle with the assumption that no counter example exists. */ - private int maxNoOfTests; - - public FuzzyStateCoverEQOracleProxy() { - this.minLength = 1; - this.maxLength = 1; - this.maxNoOfTests = 1; - this.seed = RANDOM_SEED; - } - - public FuzzyStateCoverEQOracleProxy(int minLength, int maxLength, int maxNoOfTests, int seed) { - this.minLength = minLength; - this.maxLength = maxLength; - this.maxNoOfTests = maxNoOfTests; - this.seed = seed; - } - - @Override - public void checkParameters() throws IllegalArgumentException { - if (minLength < 0 || maxLength < 0) { - throw new IllegalArgumentException( - "Fuzzy State Cover EQ Oracle: min length and max length must not be negative."); - } else if (minLength > maxLength) { - throw new IllegalArgumentException( - "Fuzzy State Cover EQ Oracle: max depth must be greater or equal to min depth."); - } else if (maxNoOfTests < 1) { - throw new IllegalArgumentException( - "Fuzzy State Cover EQ Oracle: max no of test must be greater than 0."); - } - } - - @Override - public EquivalenceOracle, String, Word> createEqOracle( - MembershipOracle> mqOracle) { - return new FuzzyStateCoverEQOracle<>(mqOracle, minLength, maxLength, maxNoOfTests, new Random(seed), batchSize); - } - - public int getMinLength() { - return minLength; - } - - public void setMinLength(int minLength) { - this.minLength = minLength; - } - - public int getMaxLength() { - return maxLength; - } - - public void setMaxLength(int maxLength) { - this.maxLength = maxLength; - } - - public int getMaxNoOfTests() { - return maxNoOfTests; - } - - public void setMaxNoOfTests(int maxNoOfTests) { - this.maxNoOfTests = maxNoOfTests; - } - - public int getSeed() { - return seed; - } - - public void setSeed(int seed) { - this.seed = seed; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/HypothesisEQOracleProxy.java b/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/HypothesisEQOracleProxy.java deleted file mode 100644 index 01c024b93..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/HypothesisEQOracleProxy.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.learnlibproxies.eqproxies; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.learning.entities.learnlibproxies.CompactMealyMachineProxy; -import de.learnlib.api.oracle.EquivalenceOracle; -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.oracle.equivalence.SimulatorEQOracle; -import java.io.Serializable; -import net.automatalib.automata.transducers.MealyMachine; -import net.automatalib.automata.transducers.impl.compact.CompactMealy; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; - -/** - * Proxy around a {@link de.learnlib.oracle.equivalence.SimulatorEQOracle}. - * The Proxy is needed to make it easier to (de-)serialize the Transition into/ from JSON. - */ -@JsonTypeName("hypothesis") -public class HypothesisEQOracleProxy extends AbstractEquivalenceOracleProxy implements Serializable { - - private static final long serialVersionUID = -110995671060498443L; - - /** The Hypothesis to check against. */ - private CompactMealyMachineProxy hypothesis; - - public CompactMealyMachineProxy getHypothesis() { - return hypothesis; - } - - public void setHypothesis(CompactMealyMachineProxy hypothesis) { - this.hypothesis = hypothesis; - } - - @Override - public void checkParameters() throws IllegalArgumentException { - if (hypothesis == null || hypothesis.getNodes().size() == 0) { - throw new IllegalArgumentException("Invalid Hypothesis to compare!"); - } - } - - @Override - public EquivalenceOracle, String, Word> createEqOracle( - MembershipOracle> membershipOracle) { - Alphabet alphabet = hypothesis.createAlphabet(); - CompactMealy compactMealy = hypothesis.createMealyMachine(alphabet); - return new SimulatorEQOracle<>(compactMealy); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/MealyRandomWordsEQOracleProxy.java b/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/MealyRandomWordsEQOracleProxy.java deleted file mode 100644 index e3eb92c20..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/MealyRandomWordsEQOracleProxy.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.learnlibproxies.eqproxies; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.api.oracle.EquivalenceOracle; -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.oracle.equivalence.RandomWordsEQOracle; -import java.io.Serializable; -import java.util.Random; -import net.automatalib.automata.transducers.MealyMachine; -import net.automatalib.words.Word; - -@JsonTypeName("random_word") -public class MealyRandomWordsEQOracleProxy extends AbstractEquivalenceOracleProxy implements Serializable { - - /** The seed to use for the RNG. */ - public static final int RANDOM_SEED = 42; - - /** The minimal length of the random generated words. */ - private int minLength; - - /** The maximal length of the random generated words. */ - private int maxLength; - - /** The seed to use for the random number generator. */ - private int seed; - - /** How many words should be created before ending the oracle with the assumption that no counter example exists. */ - private int maxNoOfTests; - - public MealyRandomWordsEQOracleProxy() { - this.minLength = 1; - this.maxLength = 1; - this.maxNoOfTests = 1; - this.seed = RANDOM_SEED; - } - - public MealyRandomWordsEQOracleProxy(int minLength, int maxLength, int maxNoOfTests, int seed) { - this.minLength = minLength; - this.maxLength = maxLength; - this.maxNoOfTests = maxNoOfTests; - this.seed = seed; - } - - public int getMinLength() { - return minLength; - } - - public void setMinLength(int minLength) { - this.minLength = minLength; - } - - public int getMaxLength() { - return maxLength; - } - - public void setMaxLength(int maxLength) { - this.maxLength = maxLength; - } - - public int getMaxNoOfTests() { - return maxNoOfTests; - } - - public void setMaxNoOfTests(int maxNoOfTests) { - this.maxNoOfTests = maxNoOfTests; - } - - public int getSeed() { - return seed; - } - - public void setSeed(int seed) { - this.seed = seed; - } - - @Override - public void checkParameters() throws IllegalArgumentException { - if (minLength < 0 || maxLength < 0) { - throw new IllegalArgumentException( - "Random Word EQ Oracle: min length and max length must not be negative."); - } else if (minLength > maxLength) { - throw new IllegalArgumentException( - "Random Word EQ Oracle: max depth must be greater or equal to min depth."); - } else if (maxNoOfTests < 1) { - throw new IllegalArgumentException( - "Random Word EQ Oracle: max no of test must be greater than 0."); - } - } - - @Override - public EquivalenceOracle, String, Word> createEqOracle( - MembershipOracle> membershipOracle) { - return new RandomWordsEQOracle<>(membershipOracle, minLength, maxLength, maxNoOfTests, new Random(seed), batchSize); - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/SampleEQOracleProxy.java b/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/SampleEQOracleProxy.java deleted file mode 100644 index cca2097d0..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/SampleEQOracleProxy.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.learnlibproxies.eqproxies; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.api.oracle.EquivalenceOracle; -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.oracle.equivalence.SampleSetEQOracle; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Stream; -import javax.validation.constraints.NotBlank; -import net.automatalib.automata.transducers.MealyMachine; -import net.automatalib.words.Word; - -/** - * Proxy around a {@link de.learnlib.oracle.equivalence.SampleSetEQOracle}. - * The Proxy is needed to make it easier to (de-)serialize the Transition into/ from JSON. - */ -@JsonTypeName("sample") -public class SampleEQOracleProxy extends AbstractEquivalenceOracleProxy implements Serializable { - - private static final long serialVersionUID = -110995671060498443L; - - /** - * Construct to hold a pair of an input and output string. - */ - public static class InputOutputPair implements Serializable { - - private static final long serialVersionUID = 2200629936714510637L; - - /** The input. */ - @NotBlank - private String input; - - /** The output that should occur. */ - @NotBlank - private String output; - - /** - * Default constructor. - */ - public InputOutputPair() { - } - - /** - * Constructor. - * - * @param input - * The input symbol. - * @param output - * The output symbol. - */ - public InputOutputPair(String input, String output) { - this.input = input; - this.output = output; - } - - /** - * Get the input. - * - * @return The input. - */ - public String getInput() { - return input; - } - - /** - * Set the input. - * - * @param input - * The input. - */ - public void setInput(String input) { - this.input = input; - } - - /** - * Get the output. - * - * @return The output. - */ - public String getOutput() { - return output; - } - - /** - * Set the output. - * - * @param output - * The output. - */ - public void setOutput(String output) { - this.output = output; - } - - @Override - public String toString() { - return "(" + input + "/" + output + ")"; - } - } - - /** A list of counter examples. */ - private List> counterExamples; - - /** - * Default constructor. - */ - public SampleEQOracleProxy() { - this.counterExamples = new ArrayList<>(); - } - - /** - * Get the list of all counter examples that should be used during the learning process. - * - * @return A list of counter examples. - */ - public List> getCounterExamples() { - return counterExamples; - } - - /** - * Set a new list of counter examples to use during a learning process. - * - * @param counterExamples - * The new counter examples to check. - */ - public void setCounterExamples(List> counterExamples) { - this.counterExamples = counterExamples; - } - - @Override - public void checkParameters() throws IllegalArgumentException { - } - - /** - * Add one counter example to the list of examples to check. - * - * @param counterExample - * The new example to verify. - */ - public void addCounterExample(List counterExample) { - this.counterExamples.add(counterExample); - } - - @Override - public EquivalenceOracle, String, Word> createEqOracle( - MembershipOracle> membershipOracle) { - SampleSetEQOracle newEQ = new SampleSetEQOracle(false); - - for (List counterExample : counterExamples) { - Stream inputOutputPairStream = counterExample.stream(); - String[] inputs = inputOutputPairStream.map(InputOutputPair::getInput).toArray(String[]::new); - Word input = Word.fromArray(inputs, 0, inputs.length); - inputOutputPairStream = counterExample.stream(); - String[] outputs = inputOutputPairStream.map(InputOutputPair::getOutput).toArray(String[]::new); - Word output = Word.fromArray(outputs, 0, outputs.length); - newEQ.add(input, output); - } - - return newEQ; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/TestSuiteEQOracleProxy.java b/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/TestSuiteEQOracleProxy.java deleted file mode 100644 index 4a0b2b40d..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/TestSuiteEQOracleProxy.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.learnlibproxies.eqproxies; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.testing.dao.TestDAO; -import de.learnlib.api.oracle.EquivalenceOracle; -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.api.query.DefaultQuery; -import java.io.Serializable; -import java.util.ArrayDeque; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Queue; -import java.util.stream.Collectors; -import javax.annotation.Nullable; -import net.automatalib.automata.transducers.MealyMachine; -import net.automatalib.words.Word; - -/** - * Use tests in a test suite as equivalence oracle. - */ -@JsonTypeName("test_suite") -public class TestSuiteEQOracleProxy extends AbstractEquivalenceOracleProxy - implements Serializable, EquivalenceOracle.MealyEquivalenceOracle { - - private static final long serialVersionUID = -3870595994346964299L; - - /** The ID of the test suite to use for testing. */ - private Long testSuiteId; - - /** If test cases of child test suites should be included as well. */ - private boolean includeChildTestSuites; - - /** The mq oracle. */ - private MembershipOracle> oracle; - - /** How many membership queries can be posed together. */ - private int batchSize; - - /** The test cases in the test suite. Once a test case has been tried, it is removed from the queue. */ - private final Queue> testCases; - - /** Constructor. */ - public TestSuiteEQOracleProxy() { - this.testCases = new ArrayDeque<>(); - this.includeChildTestSuites = false; - } - - /** - * Constructor. - * - * @param testSuiteId - * The ID of the test suite to use. - * @param testDAO - * The test DAO. - * @param user - * The user that is learning. - * @param result - * The current learner result that is used for getting relevant input symbols. - * @param oracle - * The oracle to use. - * @param batchSize - * How many membership queries can be posed together. - */ - public TestSuiteEQOracleProxy(Long testSuiteId, TestDAO testDAO, User user, LearnerResult result, - MembershipOracle> oracle, int batchSize) { - this(); - this.testSuiteId = testSuiteId; - this.oracle = oracle; - this.batchSize = batchSize; - - try { - Map symbolNameMapping = new HashMap<>(); - result.getSetup().getSymbols().forEach(s -> symbolNameMapping.put(s.getId(), s.getAliasOrComputedName())); - - testDAO.getTestCases(user, result.getProjectId(), testSuiteId).forEach(tc -> { - final Word input = Word.fromList( - tc.getSteps().stream() - .map(step -> symbolNameMapping.get(step.getPSymbol().getId())) - .collect(Collectors.toList()) - ); - testCases.add(input); - }); - } catch (Exception e) { - // if something does not work, we use an empty collection which simply results in no counterexample being found. - e.printStackTrace(); - } - } - - @Override - public void checkParameters() throws IllegalArgumentException { - if (testSuiteId == null || testSuiteId < 0) { - throw new IllegalArgumentException("The ID of the test suite has to be >= 0"); - } - } - - @Override - public EquivalenceOracle, String, Word> createEqOracle( - MembershipOracle> membershipOracle) { - throw new UnsupportedOperationException("Cannot call this method on this class."); - } - - /** - * Create an instance of the equivalence oracle. Use this method instead of the default one since we require more - * classes to be available as the standard API. - * - * @param membershipOracle - * The membership oracle. - * @param testDAO - * The test DAO. - * @param user - * The current user. - * @param result - * The current result. - * @return An instance of the equivalence oracle. - */ - public EquivalenceOracle, String, Word> createEqOracle( - MembershipOracle> membershipOracle, TestDAO testDAO, User user, - LearnerResult result) { - return new TestSuiteEQOracleProxy(testSuiteId, testDAO, user, result, membershipOracle, batchSize); - } - - @Nullable - @Override - public DefaultQuery> findCounterExample(MealyMachine hyp, - Collection alphabet) { - - while (!testCases.isEmpty()) { - try { - final Word input = testCases.poll(); - final Word hypOutput = hyp.computeOutput(input); - final Word sulOutput = oracle.answerQuery(input); - - if (!hypOutput.equals(sulOutput)) { - final DefaultQuery> ce = new DefaultQuery<>(input); - ce.answer(sulOutput); - return ce; - } - } catch (Exception e) { - // if something does not work, we simply skip the word. - } - } - - return null; - } - - public Long getTestSuiteId() { - return testSuiteId; - } - - public void setTestSuiteId(Long testSuiteId) { - this.testSuiteId = testSuiteId; - } - - public boolean isIncludeChildTestSuites() { - return includeChildTestSuites; - } - - public void setIncludeChildTestSuites(boolean includeChildTestSuites) { - this.includeChildTestSuites = includeChildTestSuites; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/WMethodEQOracleProxy.java b/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/WMethodEQOracleProxy.java deleted file mode 100644 index 5eae433b8..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/WMethodEQOracleProxy.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.learnlibproxies.eqproxies; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.api.oracle.EquivalenceOracle; -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.oracle.equivalence.WMethodEQOracle; -import java.io.Serializable; -import net.automatalib.automata.transducers.MealyMachine; -import net.automatalib.words.Word; - -/** - * Proxy around a {@link WMethodEQOracle}. The Proxy is needed to make it easier to (de-)serialize the Transition into/ from - * JSON. - */ -@JsonTypeName("wmethod") -public class WMethodEQOracleProxy extends AbstractEquivalenceOracleProxy implements Serializable { - - private static final long serialVersionUID = 2016142289217760178L; - - /** The maximal depth to explore. */ - private int maxDepth; - - /** - * Default constructor. - */ - public WMethodEQOracleProxy() { - this.maxDepth = 0; - } - - /** - * Get the maximal depth to explore, i.e. the maximal length of the words to test. - * - * @return The maximal depth to explore. - */ - public int getMaxDepth() { - return maxDepth; - } - - /** - * Set a new maximum for the exploration level. - * - * @param maxDepth - * The new maximal depth to explore. - */ - public void setMaxDepth(int maxDepth) { - this.maxDepth = maxDepth; - } - - - @Override - public void checkParameters() throws IllegalArgumentException { - if (maxDepth < 0) { - throw new IllegalArgumentException("W Method EQ Oracle: max depth must not be negative."); - } - } - - @Override - public EquivalenceOracle, String, Word> createEqOracle( - MembershipOracle> membershipOracle) { - return new WMethodEQOracle<>(membershipOracle, this.maxDepth, batchSize); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/WpMethodEQOracleProxy.java b/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/WpMethodEQOracleProxy.java deleted file mode 100644 index 248527150..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/WpMethodEQOracleProxy.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.learnlibproxies.eqproxies; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.api.oracle.EquivalenceOracle; -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.oracle.equivalence.WpMethodEQOracle; -import java.io.Serializable; -import net.automatalib.automata.transducers.MealyMachine; -import net.automatalib.words.Word; - -/** - * Proxy around a {@link de.learnlib.oracle.equivalence.WMethodEQOracle}. - * The Proxy is needed to make it easier to (de-)serialize the Transition into/ from JSON. - */ -@JsonTypeName("wp_method") -public class WpMethodEQOracleProxy extends AbstractEquivalenceOracleProxy implements Serializable { - - private static final long serialVersionUID = -4694711328777712181L; - - /** The maximal depth to explore. */ - private int maxDepth; - - /** - * Default constructor. - */ - public WpMethodEQOracleProxy() { - this.maxDepth = 0; - } - - @Override - public void checkParameters() throws IllegalArgumentException { - if (maxDepth < 0) { - throw new IllegalArgumentException("Wp Method EQ Oracle: max depth must not be negative."); - } - } - - @Override - public EquivalenceOracle, String, Word> createEqOracle( - MembershipOracle> membershipOracle) { - return new WpMethodEQOracle<>(membershipOracle, maxDepth, 0, batchSize); - } - - public int getMaxDepth() { - return maxDepth; - } - - public void setMaxDepth(int maxDepth) { - this.maxDepth = maxDepth; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/events/LearnerEvent.java b/backend/src/main/java/de/learnlib/alex/learning/events/LearnerEvent.java deleted file mode 100644 index d1ae508b6..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/events/LearnerEvent.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.events; - -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.webhooks.entities.Event; -import de.learnlib.alex.webhooks.entities.EventType; - -/** Events for the learner. */ -public class LearnerEvent { - - /** Event for when the learner started. */ - public static class Started extends Event { - - /** - * Constructor. - * - * @param result - * The configuration used for starting the learner. - */ - public Started(LearnerResult result) { - super(result, EventType.LEARNER_STARTED); - } - } - - /** Event for when the learner is resumed. */ - public static class Resumed extends Event { - - /** - * Constructor. - * - * @param result - * The configuration used for resuming the learner. - */ - public Resumed(LearnerResult result) { - super(result, EventType.LEARNER_RESUMED); - } - } - - /** Event for when the learner finished. */ - public static class Finished extends Event { - - /** - * Constructor. - * - * @param result - * The learner result. - */ - public Finished(LearnerResult result) { - super(result, EventType.LEARNER_FINISHED); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/exceptions/LearnerException.java b/backend/src/main/java/de/learnlib/alex/learning/exceptions/LearnerException.java deleted file mode 100644 index 8273ce9a0..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/exceptions/LearnerException.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.exceptions; - -/** - * Exception to indicate error during the learn process. - */ -public class LearnerException extends RuntimeException { - - /** - * Calls the constructor of the super Exception class. - * - * @param message - * More details of the error as good, old string. - */ - public LearnerException(String message) { - super(message); - } - - /** - * Calls the constructor of the super Exception class. - * - * @param message - * More details of the error as good, old string. - * @param cause - * A throwable that caused the learner to stop. - */ - public LearnerException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/repositories/LearnerResultRepository.java b/backend/src/main/java/de/learnlib/alex/learning/repositories/LearnerResultRepository.java deleted file mode 100644 index bcb4a0855..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/repositories/LearnerResultRepository.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.repositories; - -import de.learnlib.alex.learning.entities.LearnerResult; -import java.util.List; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.stereotype.Repository; - -/** - * Repository to persist LearnerResults. - */ -@Repository -public interface LearnerResultRepository extends JpaRepository { - - /** - * Find all LearnerResults in a Project. - * - * @param projectId - * The ID the Project the LearnerResults belong to. - * @return The LearnerResults. - */ - List findByProject_IdOrderByTestNoAsc(Long projectId); - - /** - * Find all LearnerResults by their test no in a Project. - * - * @param projectId - * The ID the Project the LearnerResults belong to. - * @param testNos - * The test no of the LearnResults to fetch. - * @return The LearnResults. - */ - List findByProject_IdAndTestNoIn(Long projectId, List testNos); - - List findByProject_Id(Long projectId); - - Page findByProject_Id(Long projectId, Pageable pageable); - - List findByIdIn(List ids); - - /** - * Find a single learner result. - * - * @param projectId - * The ID of the project. - * @param testNo - * The test number. - * @return The learner result. - */ - LearnerResult findOneByProject_IdAndTestNo(Long projectId, Long testNo); - - /** - * Get the highest / latest test no used in a Project. - * - * @param projectId - * The ID of the Project to check. - * @return The highest test no within that project. - */ - @Query("SELECT MAX(l.testNo) FROM LearnerResult l WHERE l.project.id = ?1") - Long findHighestTestNo(Long projectId); - - /** - * Get the latest learner result. - * - * @param projectId - * The id of the project. - * @return The latest learner result. - */ - LearnerResult findFirstByProject_IdOrderByTestNoDesc(Long projectId); - - /** - * Delete LearnResults by their test no in a Project. - * - * @param projectId - * The ID the Project the LearnerResults belong to. - * @param testNos - * The test no of the LearnResults to delete. - * @return The amount of deleted LearnResults. - */ - Long deleteByProject_IdAndTestNoIn(Long projectId, List testNos); - - /** - * Delete all learner results in a project. - * - * @param projectId - * The ID of the project. - * @return The amount of deleted LearnResults. - */ - Long deleteAllByProject_Id(Long projectId); - - List findAllByStatusIn(List statusList); - - Long countAllBySetup_Id(Long setupId); -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/repositories/LearnerResultStepRepository.java b/backend/src/main/java/de/learnlib/alex/learning/repositories/LearnerResultStepRepository.java deleted file mode 100644 index 9572c5276..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/repositories/LearnerResultStepRepository.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.repositories; - -import de.learnlib.alex.learning.entities.LearnerResultStep; -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** - * Repository to persist LearnerResultSteps. - */ -@Repository -public interface LearnerResultStepRepository extends JpaRepository { - - void deleteAllByIdIn(List stepIds); - - void deleteAllByResult_Project_Id(Long projectId); - - List findAllByResult_Project_Id(Long projectId); -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/repositories/LearnerSetupRepository.java b/backend/src/main/java/de/learnlib/alex/learning/repositories/LearnerSetupRepository.java deleted file mode 100644 index 1088074a2..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/repositories/LearnerSetupRepository.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.repositories; - -import de.learnlib.alex.learning.entities.LearnerSetup; -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; - -@Repository -public interface LearnerSetupRepository extends JpaRepository { - - List findAllByProject_Id(Long projectId); - - void deleteAllByProject_Id(Long projectId); - - @Query(value = "select ls " - + "from LearnerSetup ls join ls.environments e " - + "where ls.project.id = :projectId and e.id = :environmentId") - List findAllByProject_IdAndEnvironment_Id(@Param("projectId") Long projectId, @Param("environmentId") Long environmentId); -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/rest/LearnerResource.java b/backend/src/main/java/de/learnlib/alex/learning/rest/LearnerResource.java deleted file mode 100644 index 45f6e8087..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/rest/LearnerResource.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.rest; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.learning.entities.DifferenceTreeInput; -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.learning.entities.LearnerResumeConfiguration; -import de.learnlib.alex.learning.entities.LearnerStartConfiguration; -import de.learnlib.alex.learning.entities.LearnerStatus; -import de.learnlib.alex.learning.entities.SeparatingWord; -import de.learnlib.alex.learning.entities.learnlibproxies.CompactMealyMachineProxy; -import de.learnlib.alex.learning.events.LearnerEvent; -import de.learnlib.alex.learning.rest.inputs.StopLearnerProcessInput; -import de.learnlib.alex.learning.services.LearnerService; -import de.learnlib.alex.security.AuthContext; -import de.learnlib.alex.webhooks.services.WebhookService; -import java.util.List; -import javax.ws.rs.core.MediaType; -import net.automatalib.automata.transducers.impl.compact.CompactMealy; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * REST API to manage the learning. - */ -@RestController -@Transactional(rollbackFor = Exception.class) -@RequestMapping("/rest/projects/{projectId}/learner") -public class LearnerResource { - - private final AuthContext authContext; - private final ProjectDAO projectDAO; - private final LearnerService learnerService; - private final WebhookService webhookService; - - @Autowired - public LearnerResource(AuthContext authContext, - ProjectDAO projectDAO, - LearnerService learnerService, - WebhookService webhookService - ) { - this.authContext = authContext; - this.projectDAO = projectDAO; - this.learnerService = learnerService; - this.webhookService = webhookService; - } - - /** - * Start the learning. - * - * @param projectId - * The project to learn. - * @param startConfiguration - * The learner setup. - * @return The status of the current learn process. - */ - @PostMapping( - value = "/start", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity start(@PathVariable("projectId") Long projectId, - @RequestBody LearnerStartConfiguration startConfiguration) { - final User user = authContext.getUser(); - - if (startConfiguration.getSetup().getSymbols().contains(startConfiguration.getSetup().getPreSymbol())) { - throw new IllegalArgumentException("The reset may not be a part of the input alphabet"); - } - - final Project project = projectDAO.getByID(user, projectId); - final LearnerResult learnerResult = learnerService.start(user, project, startConfiguration); - - webhookService.fireEvent(user, new LearnerEvent.Started(learnerResult)); - return ResponseEntity.ok(learnerResult); - } - - /** - * Resume the learning. The project id and the test no must be the same as the very last started learn process. The - * server must not be restarted - * - * @param projectId - * The project to learn. - * @param testNo - * The number of the test run which should be resumed. - * @param configuration - * The configuration to specify the settings for the next learning steps. - * @return The status of the current learn process. - */ - @PostMapping( - value = "/{testNo}/resume", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity resume(@PathVariable("projectId") Long projectId, - @PathVariable("testNo") Long testNo, - @RequestBody LearnerResumeConfiguration configuration) { - final var user = authContext.getUser(); - final var result = learnerService.resume(user, projectId, testNo, configuration); - webhookService.fireEvent(user, new LearnerEvent.Resumed(result)); - return ResponseEntity.ok(result); - } - - /** - * Stop the learning after the current step. This does not stop the learning immediately! This will always return - * OK, even if there is nothing to stop. To see if there is currently a learning process, the status like '/active' - * will be returned. - * - * @param input - * The data to use for stopping the learner process. - * @return The status of the current learn process. - */ - @PostMapping( - value = "/stop" - ) - public ResponseEntity stop(@Validated @RequestBody StopLearnerProcessInput input) { - final var user = authContext.getUser(); - learnerService.abort(user, input.projectId, input.resultId); - return ResponseEntity.ok().build(); - } - - /** - * Get the parameters & (temporary) results of the learning. - * - * @param projectId - * The project to get the Status of. - * @return The information of the learning - */ - @GetMapping( - value = "/status", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity getStatus(@PathVariable("projectId") Long projectId) { - final var user = authContext.getUser(); - final var status = learnerService.getStatus(user, projectId); - return ResponseEntity.ok(status); - } - - /** - * Test if two hypotheses are equal or not. If a difference was found the separating word will be returned. - * Otherwise, i.e. the hypotheses are equal. - * - * @param mealyMachineProxies - * A List of two (!) hypotheses, which will be compared. - * @return '{"separatingWord": "separating word, if any"}' - */ - @PostMapping( - value = "/compare/separatingWord", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity separatingWord( - @PathVariable("projectId") Long projectId, - @RequestBody List mealyMachineProxies - ) { - if (mealyMachineProxies.size() != 2) { - throw new IllegalArgumentException("You need to specify exactly two hypotheses!"); - } - - final var diff = learnerService.separatingWord(mealyMachineProxies.get(0), mealyMachineProxies.get(1)); - return ResponseEntity.ok(diff); - } - - /** - * Calculates the difference tree of two hypotheses. - * - * @param input - * A List of two (!) hypotheses, which will be compared. - * @return The difference tree - */ - @PostMapping( - value = "/compare/differenceTree", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity differenceTree( - @PathVariable("projectId") Long projectId, - @RequestBody @Validated DifferenceTreeInput input - ) { - final var user = authContext.getUser(); - final var differenceTree = learnerService.differenceTree(user, projectId, input); - final var proxy = CompactMealyMachineProxy.createFrom(differenceTree, differenceTree.getInputAlphabet()); - return ResponseEntity.ok(proxy); - } - - @PostMapping( - value = "/compare/differenceAutomaton", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity differenceAutomaton( - @PathVariable("projectId") Long projectId, - @RequestBody List mealyMachineProxies - ) { - if (mealyMachineProxies.size() != 2) { - throw new IllegalArgumentException("You need to specify exactly two hypotheses!"); - } - - final var diffAutomaton = learnerService.differenceAutomaton( - mealyMachineProxies.get(0), - mealyMachineProxies.get(1) - ); - - return ResponseEntity.ok(CompactMealyMachineProxy.createFrom(diffAutomaton, diffAutomaton.getInputAlphabet())); - } -} - diff --git a/backend/src/main/java/de/learnlib/alex/learning/rest/LearnerResultResource.java b/backend/src/main/java/de/learnlib/alex/learning/rest/LearnerResultResource.java deleted file mode 100644 index 91c77e567..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/rest/LearnerResultResource.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.rest; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.learning.dao.LearnerResultDAO; -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.learning.entities.ModelExportFormat; -import de.learnlib.alex.learning.entities.TestSuiteGenerationConfig; -import de.learnlib.alex.learning.rest.inputs.UpdateLearnerResultInput; -import de.learnlib.alex.learning.services.ModelExporter; -import de.learnlib.alex.learning.services.TestGenerator; -import de.learnlib.alex.security.AuthContext; -import de.learnlib.alex.testing.entities.TestSuite; -import java.io.IOException; -import java.util.List; -import javax.validation.Valid; -import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Sort; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -/** - * REST API to fetch the test results. - */ -@RestController -@RequestMapping("/rest/projects/{projectId}/results") -public class LearnerResultResource { - - private final AuthContext authContext; - private final LearnerResultDAO learnerResultDAO; - private final TestGenerator testGenerator; - private final ModelExporter modelExporter; - - @Autowired - public LearnerResultResource(AuthContext authContext, - LearnerResultDAO learnerResultDAO, - TestGenerator testGenerator, - ModelExporter modelExporter) { - this.authContext = authContext; - this.learnerResultDAO = learnerResultDAO; - this.testGenerator = testGenerator; - this.modelExporter = modelExporter; - } - - /** - * Get all learn results one project. - * - * @param projectId - * The project of the learn results. - * @return A List of all learn results within one project. - */ - @GetMapping( - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity getAll(@PathVariable("projectId") Long projectId, - @RequestParam(name = "page", required = false) String page, - @RequestParam(name = "size", required = false) String size) { - final User user = authContext.getUser(); - - if ((page == null && size != null) || (size == null && page != null)) { - throw new IllegalArgumentException("'page' and 'size' params have to be used in combination."); - } - - if (page == null) { - final List results = learnerResultDAO.getAll(user, projectId); - return ResponseEntity.ok(results); - } else { - final PageRequest pr = PageRequest.of( - Integer.parseInt(page), - Integer.parseInt(size), - Sort.by(Sort.Direction.DESC, "testNo") - ); - final Page resultPage = learnerResultDAO.getAll(user, projectId, pr); - return ResponseEntity.ok(resultPage); - } - } - - /** - * Get the latest learner result. - * - * @param projectId - * The id of the project. - * @return 200 with The latest learner result. 204 If there is not result. - */ - @GetMapping( - value = "/latest", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity getLatest(@PathVariable("projectId") Long projectId) { - final User user = authContext.getUser(); - final LearnerResult result = learnerResultDAO.getLatest(user, projectId); - return result == null ? ResponseEntity.noContent().build() : ResponseEntity.ok(result); - } - - /** - * Get one / a list of learn result(s). - * - * @param projectId - * The project of the learn result(s). - * @param testNos - * The number(s) of the learn result(s). - * @return A List of all step of possible multiple test runs. - */ - @GetMapping( - value = "/{testNos}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity getAll(@PathVariable("projectId") Long projectId, - @PathVariable("testNos") List testNos) { - final User user = authContext.getUser(); - if (testNos.size() == 1) { - final LearnerResult result = learnerResultDAO.getByTestNo(user, projectId, testNos.get(0)); - return ResponseEntity.ok(result); - } else { - final List results = learnerResultDAO.getAll(user, projectId, testNos); - return ResponseEntity.ok(results); - } - } - - /** - * Clone a learner result. - * - * @param projectId - * The ID of the project. - * @param testNo - * The test no of the learner result to clone. - * @return The cloned learner result. - */ - @PostMapping( - value = "/{testNo}/copy", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity copy( - @PathVariable("projectId") Long projectId, - @PathVariable("testNo") Long testNo - ) { - final User user = authContext.getUser(); - final LearnerResult clonedResult = learnerResultDAO.copy(user, projectId, testNo); - return ResponseEntity.status(HttpStatus.CREATED).body(clonedResult); - } - - /** - * Update meta data of a learner result. - * - * @param projectId - * The ID of the project. - * @param testNo - * The test not of the learner result. - * @param input - * The object to update the learner result with. - * @return The updated learner result. - */ - @PutMapping( - value = "/{testNo}", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity update( - @PathVariable("projectId") Long projectId, - @PathVariable("testNo") Long testNo, - @RequestBody @Validated UpdateLearnerResultInput input - ) { - final var user = authContext.getUser(); - final var updatedResult = learnerResultDAO.update(user, projectId, testNo, input); - return ResponseEntity.status(HttpStatus.OK).body(updatedResult); - } - - @PostMapping( - value = "/{testNo}/steps/{stepNo}/export", - produces = MediaType.TEXT_PLAIN - ) - public ResponseEntity export( - @PathVariable("projectId") Long projectId, - @PathVariable("testNo") Long testNo, - @PathVariable("stepNo") Long stepNo, - @RequestParam(name = "format", defaultValue = "DOT") ModelExportFormat format - ) { - final User user = authContext.getUser(); - if (format == ModelExportFormat.DOT) { - return ResponseEntity.ok(modelExporter.exportDot(user, projectId, testNo, stepNo)); - } else { - throw new IllegalArgumentException("Invalid export format."); - } - } - - /** - * Generate a test suite from the discrimination tree. - * - * @param projectId - * The ID of the project. - * @param testNo - * The number of the learning experiment. - * @param config - * The configuration object. - * @return The generated test suite. - */ - @PostMapping( - value = "/{testNo}/generateTestSuite", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity generateTestSuite(@PathVariable("projectId") Long projectId, - @PathVariable("testNo") Long testNo, - @RequestBody @Valid TestSuiteGenerationConfig config) { - final var user = authContext.getUser(); - - try { - final TestSuite testSuite = testGenerator.generate(user, projectId, testNo, config); - return ResponseEntity.status(HttpStatus.CREATED).body(testSuite); - } catch (IOException | ClassNotFoundException e) { - throw new IllegalStateException(e); - } - } - - /** - * Delete one or more learn result(s). - * - * @param projectId - * The project of the learn results. - * @param testNos - * The test numbers of the results to delete as a comma (',') separated list. E.g. 1,2,3 - * @return On success no content will be returned. - */ - @DeleteMapping( - value = "/{testNos}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity deleteResults(@PathVariable("projectId") Long projectId, - @PathVariable("testNos") List testNos) { - final User user = authContext.getUser(); - learnerResultDAO.deleteByTestNos(user, projectId, testNos); - return ResponseEntity.status(HttpStatus.NO_CONTENT).build(); - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/rest/LearnerResultStepResource.java b/backend/src/main/java/de/learnlib/alex/learning/rest/LearnerResultStepResource.java deleted file mode 100644 index 64fca9510..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/rest/LearnerResultStepResource.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.rest; - -import de.learnlib.alex.learning.dao.LearnerResultStepDAO; -import de.learnlib.alex.modelchecking.services.reporters.JUnitModelCheckingResultReporter; -import de.learnlib.alex.security.AuthContext; -import java.util.List; -import javax.validation.ValidationException; -import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/rest/projects/{projectId}/results/{resultId}/steps") -@Transactional(rollbackFor = Exception.class) -public class LearnerResultStepResource { - - private final AuthContext authContext; - private final LearnerResultStepDAO learnerResultStepDAO; - - @Autowired - public LearnerResultStepResource( - AuthContext authContext, - LearnerResultStepDAO learnerResultStepDAO - ) { - this.authContext = authContext; - this.learnerResultStepDAO = learnerResultStepDAO; - } - - @GetMapping( - value = "/{stepId}/modelCheckingResults", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity getModelCheckingResults( - @PathVariable("projectId") Long projectId, - @PathVariable("resultId") Long resultId, - @PathVariable("stepId") Long stepId, - @RequestParam(name = "format", defaultValue = "json", required = false) String format - ) { - final var user = authContext.getUser(); - final var step = learnerResultStepDAO.getById(user, projectId, resultId, stepId); - - switch (format.trim().toLowerCase()) { - case "json": - return ResponseEntity.ok(step.getModelCheckingResults()); - case "junit": - final var report = new JUnitModelCheckingResultReporter().createReport(step); - return ResponseEntity.status(HttpStatus.OK) - .header("Content-Type", "application/xml") - .body(report); - default: - throw new ValidationException("Invalid format. Allowed values are 'json' and 'junit'"); - } - } - - @PostMapping( - value = "/{stepId}/hypothesis/outputs", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity getHypothesisOutputs( - @PathVariable("projectId") Long projectId, - @PathVariable("resultId") Long resultId, - @PathVariable("stepId") Long stepId, - @RequestBody List input - ) { - final var user = authContext.getUser(); - final var step = learnerResultStepDAO.getById(user, projectId, resultId, stepId); - - final var alphabet = step.getHypothesis().createAlphabet(); - final var hypothesis = step.getHypothesis().createMealyMachine(alphabet); - final var output = hypothesis.computeOutput(input).asList(); - - return ResponseEntity.ok(output); - } - -} - diff --git a/backend/src/main/java/de/learnlib/alex/learning/rest/LearnerSetupResource.java b/backend/src/main/java/de/learnlib/alex/learning/rest/LearnerSetupResource.java deleted file mode 100644 index c167e4da4..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/rest/LearnerSetupResource.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.rest; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.learning.dao.LearnerSetupDAO; -import de.learnlib.alex.learning.entities.LearnerOptions; -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.learning.entities.LearnerSetup; -import de.learnlib.alex.learning.entities.LearnerStartConfiguration; -import de.learnlib.alex.learning.services.LearnerService; -import de.learnlib.alex.security.AuthContext; -import java.util.List; -import java.util.stream.Collectors; -import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/rest/projects/{projectId}/learner/setups") -public class LearnerSetupResource { - - private final AuthContext authContext; - private final LearnerSetupDAO learnerSetupDAO; - private final LearnerService learnerService; - private final ProjectDAO projectDAO; - - @Autowired - public LearnerSetupResource(AuthContext authContext, - LearnerSetupDAO learnerSetupDAO, - ProjectDAO projectDAO, - LearnerService learnerService) { - this.authContext = authContext; - this.learnerSetupDAO = learnerSetupDAO; - this.projectDAO = projectDAO; - this.learnerService = learnerService; - } - - @GetMapping( - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> getAll(@PathVariable("projectId") Long projectId) { - final User user = authContext.getUser(); - final List setups = learnerSetupDAO.getAll(user, projectId).stream() - .filter(LearnerSetup::isSaved) - .collect(Collectors.toList()); - return ResponseEntity.ok(setups); - } - - @GetMapping( - value = "/{setupId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity getById(@PathVariable("projectId") Long projectId, - @PathVariable("setupId") Long setupId) { - final User user = authContext.getUser(); - final LearnerSetup setup = learnerSetupDAO.getById(user, projectId, setupId); - return ResponseEntity.ok(setup); - } - - @PostMapping( - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity create(@PathVariable("projectId") Long projectId, - @RequestBody @Validated LearnerSetup learnerSetup) { - final User user = authContext.getUser(); - learnerSetup.setSaved(true); - final LearnerSetup createdSetup = learnerSetupDAO.create(user, projectId, learnerSetup); - return ResponseEntity.status(HttpStatus.CREATED).body(createdSetup); - } - - @PutMapping( - value = "/{setupId}", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity update(@PathVariable("projectId") Long projectId, - @PathVariable("setupId") Long setupId, - @RequestBody LearnerSetup learnerSetup) { - final User user = authContext.getUser(); - final LearnerSetup updatedSetup = learnerSetupDAO.update(user, projectId, setupId, learnerSetup); - return ResponseEntity.ok(updatedSetup); - } - - @PostMapping( - value = "/{setupId}/copy", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity copy(@PathVariable("projectId") Long projectId, - @PathVariable("setupId") Long setupId) { - final User user = authContext.getUser(); - final LearnerSetup copiedSetup = learnerSetupDAO.copy(user, projectId, setupId, true); - return ResponseEntity.ok(copiedSetup); - } - - @DeleteMapping( - value = "/{setupId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity delete(@PathVariable("projectId") Long projectId, - @PathVariable("setupId") Long setupId) { - final User user = authContext.getUser(); - learnerSetupDAO.delete(user, projectId, setupId); - return ResponseEntity.noContent().build(); - } - - @PostMapping( - value = "/{setupId}/run", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity run(@PathVariable("projectId") Long projectId, - @PathVariable("setupId") Long setupId, - @RequestBody(required = false) LearnerOptions options) { - final User user = authContext.getUser(); - final Project project = projectDAO.getByID(user, projectId); - final LearnerSetup setup = learnerSetupDAO.copy(user, projectId, setupId, false); - - final LearnerStartConfiguration startConfiguration = new LearnerStartConfiguration(); - startConfiguration.setOptions(options); - startConfiguration.setSetup(setup); - - final LearnerResult result = learnerService.start(user, project, startConfiguration); - return ResponseEntity.ok(result); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/rest/inputs/StopLearnerProcessInput.java b/backend/src/main/java/de/learnlib/alex/learning/rest/inputs/StopLearnerProcessInput.java deleted file mode 100644 index 37f66fc9b..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/rest/inputs/StopLearnerProcessInput.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.rest.inputs; - -import javax.validation.constraints.NotNull; - -public class StopLearnerProcessInput { - - @NotNull - public Long projectId; - - @NotNull - public Long resultId; -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/rest/inputs/UpdateLearnerResultInput.java b/backend/src/main/java/de/learnlib/alex/learning/rest/inputs/UpdateLearnerResultInput.java deleted file mode 100644 index ccc795cfa..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/rest/inputs/UpdateLearnerResultInput.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.rest.inputs; - -import javax.validation.constraints.NotNull; - -public class UpdateLearnerResultInput { - - @NotNull - public String comment; -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/AbstractLearnerProcess.java b/backend/src/main/java/de/learnlib/alex/learning/services/AbstractLearnerProcess.java deleted file mode 100644 index ada6488f2..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/AbstractLearnerProcess.java +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services; - -import de.learnlib.alex.auth.dao.UserDAO; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.learning.dao.LearnerResultDAO; -import de.learnlib.alex.learning.dao.LearnerResultStepDAO; -import de.learnlib.alex.learning.dao.LearnerSetupDAO; -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.learning.entities.LearnerResult.Status; -import de.learnlib.alex.learning.entities.LearnerResultStep; -import de.learnlib.alex.learning.entities.LearnerSetup; -import de.learnlib.alex.learning.entities.learnlibproxies.CompactMealyMachineProxy; -import de.learnlib.alex.learning.entities.learnlibproxies.DefaultQueryProxy; -import de.learnlib.alex.learning.entities.learnlibproxies.eqproxies.AbstractEquivalenceOracleProxy; -import de.learnlib.alex.learning.entities.learnlibproxies.eqproxies.TestSuiteEQOracleProxy; -import de.learnlib.alex.learning.services.connectors.PreparedConnectorContextHandlerFactory; -import de.learnlib.alex.learning.services.connectors.PreparedContextHandler; -import de.learnlib.alex.learning.services.oracles.ContextAwareSulOracle; -import de.learnlib.alex.learning.services.oracles.DelegationOracle; -import de.learnlib.alex.learning.services.oracles.QueryMonitorOracle; -import de.learnlib.alex.learning.services.oracles.StatisticsOracle; -import de.learnlib.alex.modelchecking.services.ModelCheckerService; -import de.learnlib.alex.testing.dao.TestDAO; -import de.learnlib.alex.webhooks.services.WebhookService; -import de.learnlib.api.algorithm.LearningAlgorithm; -import de.learnlib.api.oracle.EquivalenceOracle; -import de.learnlib.api.query.DefaultQuery; -import de.learnlib.filter.cache.mealy.MealyCacheOracle; -import de.learnlib.oracle.parallelism.DynamicParallelOracleBuilder; -import io.reactivex.rxjava3.subjects.BehaviorSubject; -import io.reactivex.rxjava3.subjects.Subject; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.stream.Collectors; -import net.automatalib.automata.transducers.MealyMachine; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; -import net.automatalib.words.impl.GrowingMapAlphabet; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.transaction.support.TransactionTemplate; - -/** - * Thread to run a learning process. It needs to be a Thread so that the server can still deal with other requests. This - * class contains the actual learning loop. - */ -public abstract class AbstractLearnerProcess { - - protected static final Logger logger = LoggerFactory.getLogger(AbstractLearnerProcess.class); - - protected final UserDAO userDAO; - protected final ProjectDAO projectDAO; - protected final LearnerSetupDAO learnerSetupDAO; - protected final LearnerResultDAO learnerResultDAO; - protected final LearnerResultStepDAO learnerResultStepDAO; - protected final TestDAO testDAO; - protected final WebhookService webhookService; - protected final PreparedConnectorContextHandlerFactory contextHandlerFactory; - protected final TransactionTemplate transactionTemplate; - protected final ModelCheckerService modelCheckerService; - - /** The user who is stating the Learning Thread. */ - protected User user; - - /** The current project. */ - protected Project project; - - /** The learner result. */ - protected LearnerResult result; - - /** The learner setup. */ - protected LearnerSetup setup; - - /** The queries that are executed at the moment. */ - private List currentQueries; - - /** The learner to use during the learning. */ - protected LearningAlgorithm.MealyLearner learner; - - /** The phase of the learner. */ - protected LearnerService.LearnerPhase learnerPhase; - - /** The abstract alphabet that is used during the learning process. */ - protected Alphabet abstractAlphabet; - - /** The membership oracle on the upmost level that all queries are posed to. */ - protected DelegationOracle mqOracle; - - /** Maps an abstract alphabet to a concrete one. */ - protected SymbolMapper symbolMapper; - - /** The oracle that monitors which queries are being posed. */ - protected QueryMonitorOracle monitorOracle; - - protected StatisticsOracle> counterOracle; - - protected PreparedContextHandler preparedContextHandler; - - protected List sulOracles; - - protected MealyCacheOracle cacheOracle; - - protected AbstractEquivalenceOracleProxy equivalenceOracleProxy; - - protected EquivalenceOracle, String, Word> equivalenceOracle; - - private final Subject abortSubject = BehaviorSubject.createDefault(false); - - public AbstractLearnerProcess( - UserDAO userDAO, - ProjectDAO projectDAO, - LearnerResultDAO learnerResultDAO, - LearnerSetupDAO learnerSetupDAO, - LearnerResultStepDAO learnerResultStepDAO, - TestDAO testDAO, - WebhookService webhookService, - PreparedConnectorContextHandlerFactory contextHandlerFactory, - TransactionTemplate transactionTemplate, - ModelCheckerService modelCheckerService - ) { - this.userDAO = userDAO; - this.projectDAO = projectDAO; - this.learnerResultDAO = learnerResultDAO; - this.learnerResultStepDAO = learnerResultStepDAO; - this.learnerSetupDAO = learnerSetupDAO; - this.testDAO = testDAO; - this.webhookService = webhookService; - this.contextHandlerFactory = contextHandlerFactory; - this.transactionTemplate = transactionTemplate; - this.modelCheckerService = modelCheckerService; - } - - public boolean isAbortedOrHasFailed() { - return List.of(Status.ABORTED, Status.FAILED).contains(result.getStatus()); - } - - public boolean isInitialized() { - return learner != null; - } - - protected void initInternal(C context) { - user = userDAO.getByID(context.userId); - project = projectDAO.getByID(user, context.projectId); - result = learnerResultDAO.getByID(user, context.projectId, context.resultId); - setup = learnerSetupDAO.getById(user, project.getId(), result.getSetup().getId()); - - this.abstractAlphabet = new GrowingMapAlphabet<>(new HashSet<>(// remove duplicate names with set - setup.getSymbols().stream() - .map(ParameterizedSymbol::getAliasOrComputedName) - .sorted(String::compareTo) - .collect(Collectors.toList()) - )); - - this.preparedContextHandler = contextHandlerFactory.createPreparedContextHandler( - user, result.getProject(), setup.getWebDriver(), setup.getPreSymbol(), setup.getPostSymbol()); - - this.currentQueries = new ArrayList<>(); - this.symbolMapper = new SymbolMapper(setup.getSymbols()); - - // create a sul oracle for each url - this.sulOracles = setup.getEnvironments().stream() - .map(env -> new ContextAwareSulOracle(symbolMapper, preparedContextHandler.create(env), abortSubject)) - .collect(Collectors.toList()); - - final var parallelOracle = - new DynamicParallelOracleBuilder<>(sulOracles) - .withBatchSize(1) - .withPoolSize(setup.getEnvironments().size()) - .create(); - - monitorOracle = new QueryMonitorOracle<>(parallelOracle); - monitorOracle.addPostProcessingListener(queries -> this.currentQueries = queries.stream() - .map(q -> DefaultQueryProxy.createFrom(new DefaultQuery<>(q))) - .collect(Collectors.toList())); - - counterOracle = new StatisticsOracle<>(monitorOracle); - - // create the concrete membership oracle. - this.mqOracle = new DelegationOracle<>(); - if (setup.isEnableCache()) { - this.cacheOracle = MealyCacheOracle.createDAGCacheOracle(this.abstractAlphabet, counterOracle); - this.mqOracle.setDelegate(cacheOracle); - } else { - this.mqOracle.setDelegate(counterOracle); - } - - // create the learner. - this.learner = setup.getAlgorithm().createLearner(abstractAlphabet, mqOracle); - } - - public void setEquivalenceOracle(AbstractEquivalenceOracleProxy equivalenceOracleProxy) { - this.equivalenceOracleProxy = equivalenceOracleProxy; - if (equivalenceOracleProxy instanceof TestSuiteEQOracleProxy) { - equivalenceOracle = ((TestSuiteEQOracleProxy) equivalenceOracleProxy).createEqOracle(mqOracle, testDAO, user, result); - } else { - equivalenceOracle = equivalenceOracleProxy.createEqOracle(mqOracle); - } - } - - protected void startLearningLoop() { - while (true) { - learnerPhase = LearnerService.LearnerPhase.EQUIVALENCE_TESTING; - - final var eqOracleStartTime = System.currentTimeMillis(); - final var ce = equivalenceOracle.findCounterExample(learner.getHypothesisModel(), abstractAlphabet); - final var eqOracleEndTime = System.currentTimeMillis(); - - final LearnerResultStep currentStep = result.getSteps().get(result.getSteps().size() - 1); - - transactionTemplate.execute(t -> { - final var stepToUpdate = learnerResultStepDAO.getById(user, project.getId(), result.getId(), currentStep.getId()); - stepToUpdate.getStatistics().getSymbolsUsed().setEqOracle(counterOracle.getSymbolCount()); - stepToUpdate.getStatistics().getMqsUsed().setEqOracle(counterOracle.getQueryCount()); - stepToUpdate.getStatistics().getDuration().setEqOracle(eqOracleEndTime - eqOracleStartTime); - stepToUpdate.setCounterExample(ce != null ? DefaultQueryProxy.createFrom(ce) : null); - - learnerResultStepDAO.update(stepToUpdate.getId(), stepToUpdate); - return null; - }); - - result = learnerResultDAO.getByID(user, project.getId(), result.getId()); - - counterOracle.reset(); - - if (ce != null) { - learnerPhase = LearnerService.LearnerPhase.LEARNING; - - final long learnerRefineStartTime = System.currentTimeMillis(); - learner.refineHypothesis(ce); - final long learnerRefineEndTime = System.currentTimeMillis(); - - createStep(learnerRefineEndTime, learnerRefineStartTime); - } else { - break; - } - } - } - - protected void createStep(Long endTime, Long startTime) { - final LearnerResultStep step = new LearnerResultStep(); - step.getStatistics().getSymbolsUsed().setLearner(counterOracle.getSymbolCount()); - step.getStatistics().getMqsUsed().setLearner(counterOracle.getQueryCount()); - step.getStatistics().getDuration().setLearner(endTime - startTime); - step.setEqOracle(equivalenceOracleProxy); - step.setHypothesis(CompactMealyMachineProxy.createFrom(learner.getHypothesisModel(), abstractAlphabet)); - try { - step.setState(setup.getAlgorithm().suspend(learner)); - } catch (IOException e) { - e.printStackTrace(); - } - step.setAlgorithmInformation(setup.getAlgorithm().getInternalData(learner)); - modelCheck(step); - counterOracle.reset(); - result = learnerResultDAO.addStep(result.getId(), step); - } - - abstract void init(C context); - - abstract void run(); - - public void abort() { - result = learnerResultDAO.updateStatus(result.getId(), LearnerResult.Status.ABORTED); - abortSubject.onNext(true); - } - - public LearnerService.LearnerPhase getLearnerPhase() { - return learnerPhase; - } - - public List getCurrentQueries() { - return currentQueries; - } - - public LearnerResult getResult() { - return result; - } - - private void shutdown(Status status, String errorMessage) { - result.setStatus(status); - result.setErrorMessage(errorMessage); - result = learnerResultDAO.update(result.getId(), result); - - try { - sulOracles.forEach(ContextAwareSulOracle::shutdown); - } catch (Exception e) { - logger.error(LoggerMarkers.LEARNER, "Failed to shutdown gracefully:", e); - e.printStackTrace(); - } - } - - protected void shutdownWithErrors(String errorMessage) { - shutdown(Status.FAILED, errorMessage); - } - - protected void shutdown() { - shutdown(Status.FINISHED, ""); - } - - private void modelCheck(LearnerResultStep step) { - if (!setup.getModelCheckingConfig().getFormulaSuites().isEmpty()) { - final var results = modelCheckerService.check(step, setup.getModelCheckingConfig()); - step.setModelCheckingResults(results); - } - } - - public StatisticsOracle> getCounterOracle() { - return counterOracle; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/AbstractLearnerProcessQueueItem.java b/backend/src/main/java/de/learnlib/alex/learning/services/AbstractLearnerProcessQueueItem.java deleted file mode 100644 index 59d617991..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/AbstractLearnerProcessQueueItem.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services; - -public class AbstractLearnerProcessQueueItem { - public Long userId; - public Long projectId; - public Long resultId; - - public AbstractLearnerProcessQueueItem(Long userId, Long projectId, Long resultId) { - this.userId = userId; - this.projectId = projectId; - this.resultId = resultId; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/BaseUrlManager.java b/backend/src/main/java/de/learnlib/alex/learning/services/BaseUrlManager.java deleted file mode 100644 index 67f996872..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/BaseUrlManager.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services; - -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.data.entities.ProjectUrl; -import de.learnlib.alex.data.entities.actions.Credentials; -import java.util.HashMap; -import java.util.Map; - -/** - * Class to mange a URL and get URL based on this. - */ -public class BaseUrlManager { - - private final Map urlMap; - - /** Advanced constructor which sets the base url field. */ - public BaseUrlManager(ProjectEnvironment environment) { - this.urlMap = new HashMap<>(); - environment.getUrls().forEach(u -> this.urlMap.put(u.getName(), u)); - } - - /** - * Get the absolute URL of a path, i.e. based on the base url (base url + '/' + path'), as String - * and insert the credentials if possible. - * - * @param path - * The path to append on the base url. - * @param credentials - * The credentials to insert into the URL. - * @return An absolute URL as String - */ - public String getAbsoluteUrl(String urlName, String path, Credentials credentials) { - final String url = combineUrls(urlMap.get(urlName).getUrl(), path); - return BaseUrlManager.getUrlWithCredentials(url, credentials); - } - - public String getAbsoluteUrl(String urlName, String path) { - final String url = combineUrls(urlMap.get(urlName).getUrl(), path); - return BaseUrlManager.getUrlWithCredentials(url, null); - } - - /** - * Append apiPath to basePath and make sure that only one '/' is between them. - * - * @param basePath - * The prefix of the new URL. - * @param apiPath - * The suffix of the new URL. - * @return The combined URL. - */ - private String combineUrls(String basePath, String apiPath) { - if (basePath.endsWith("/") && apiPath.startsWith("/")) { - // both have a '/' -> remove one - return basePath + apiPath.substring(1); - } else if (!basePath.endsWith("/") && !apiPath.startsWith("/")) { - // no one has a '/' -> add one - return basePath + "/" + apiPath; - } else { - // exact 1. '/' in between -> good to go - return basePath + apiPath; - } - } - - private static String getUrlWithCredentials(String url, Credentials credentials) { - if (credentials != null && credentials.areValid()) { - return url.replaceFirst("^(http[s]?://)", "$1" - + credentials.getName() + ":" - + credentials.getPassword() + "@"); - } else { - return url; - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/DifferenceSimulatorSUL.java b/backend/src/main/java/de/learnlib/alex/learning/services/DifferenceSimulatorSUL.java deleted file mode 100644 index 38f8a9959..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/DifferenceSimulatorSUL.java +++ /dev/null @@ -1,55 +0,0 @@ -package de.learnlib.alex.learning.services; - -import de.learnlib.api.SUL; -import net.automatalib.automata.transducers.impl.compact.CompactMealy; - -public class DifferenceSimulatorSUL implements SUL { - - private final String undefinedOutput; - private final CompactMealy hyp1; - private final CompactMealy hyp2; - - private Integer currentStateHyp1 = 0; - private Integer currentStateHyp2 = 0; - - private boolean differenceFound = false; - - public DifferenceSimulatorSUL( - CompactMealy hyp1, - CompactMealy hyp2, - String undefinedOutput - ) { - this.hyp1 = hyp1; - this.hyp2 = hyp2; - this.undefinedOutput = undefinedOutput; - } - - @Override - public void pre() { - currentStateHyp1 = hyp1.getInitialState(); - currentStateHyp2 = hyp2.getInitialState(); - differenceFound = false; - } - - @Override - public void post() { - } - - @Override - public String step(String o) { - if (differenceFound) return undefinedOutput; - - final var out1 = hyp1.getOutput(currentStateHyp1, o); - final var out2 = hyp2.getOutput(currentStateHyp2, o); - - currentStateHyp1 = hyp1.getSuccessor(currentStateHyp1, o); - currentStateHyp2 = hyp2.getSuccessor(currentStateHyp2, o); - - if (out1.equals(out2)) { - return out1; - } else { - differenceFound = true; - return out1 + " <-> " + out2; - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/LearnerService.java b/backend/src/main/java/de/learnlib/alex/learning/services/LearnerService.java deleted file mode 100644 index c7edde2d4..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/LearnerService.java +++ /dev/null @@ -1,662 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services; - -import de.learnlib.alex.auth.dao.UserDAO; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.common.exceptions.ResourcesExhaustedException; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.learning.dao.LearnerResultDAO; -import de.learnlib.alex.learning.dao.LearnerSetupDAO; -import de.learnlib.alex.learning.entities.DifferenceTreeInput; -import de.learnlib.alex.learning.entities.DifferenceTreeStrategy; -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.learning.entities.LearnerResult.Status; -import de.learnlib.alex.learning.entities.LearnerResultStep; -import de.learnlib.alex.learning.entities.LearnerResumeConfiguration; -import de.learnlib.alex.learning.entities.LearnerStartConfiguration; -import de.learnlib.alex.learning.entities.LearnerStatus; -import de.learnlib.alex.learning.entities.LearningProcessStatus; -import de.learnlib.alex.learning.entities.SeparatingWord; -import de.learnlib.alex.learning.entities.learnlibproxies.CompactMealyMachineProxy; -import de.learnlib.alex.testing.services.TestService; -import de.learnlib.alex.webhooks.dao.WebhookDAO; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import de.learnlib.algorithms.ttt.base.BaseTTTDiscriminationTree; -import de.learnlib.algorithms.ttt.mealy.TTTLearnerMealy; -import de.learnlib.algorithms.ttt.mealy.TTTLearnerMealyBuilder; -import de.learnlib.oracle.equivalence.WpMethodEQOracle; -import de.learnlib.oracle.membership.SULOracle; -import net.automatalib.automata.transducers.impl.compact.CompactMealy; -import net.automatalib.serialization.dot.GraphDOT; -import net.automatalib.util.automata.Automata; -import net.automatalib.util.automata.conformance.WMethodTestsIterator; -import net.automatalib.util.automata.conformance.WpMethodTestsIterator; -import net.automatalib.util.automata.transducers.MealyFilter; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; -import org.apache.shiro.authz.UnauthorizedException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.transaction.support.TransactionTemplate; - -/** - * Basic class to control and monitor a learn process. This class is a high level abstraction of the LearnLib. - */ -@Service -public class LearnerService { - - /** Indicator for in which phase the learner currently is. */ - public enum LearnerPhase { - - /** If the learner is active. */ - LEARNING, - - /** If the equivalence oracle is active. */ - EQUIVALENCE_TESTING - } - - private final LearnerSetupDAO learnerSetupDAO; - private final LearnerResultDAO learnerResultDAO; - private final ProjectDAO projectDAO; - private final ApplicationContext applicationContext; - private final TestService testService; - private final UserDAO userDAO; - private final TransactionTemplate transactionTemplate; - private final WebhookDAO webhookDAO; - - /** The learner threads for users (userId -> thread). */ - private final Map learnerThreads; - - @Autowired - public LearnerService(LearnerSetupDAO learnerSetupDAO, - LearnerResultDAO learnerResultDAO, - ApplicationContext applicationContext, - ProjectDAO projectDAO, - @Lazy TestService testService, - UserDAO userDAO, - TransactionTemplate transactionTemplate, - WebhookDAO webhookDAO) { - this.learnerSetupDAO = learnerSetupDAO; - this.learnerResultDAO = learnerResultDAO; - this.projectDAO = projectDAO; - this.applicationContext = applicationContext; - this.testService = testService; - this.userDAO = userDAO; - this.transactionTemplate = transactionTemplate; - this.webhookDAO = webhookDAO; - this.learnerThreads = new ConcurrentHashMap<>(); - } - - /** - * Start a learning process by activating a LearningThread. - * - * @param user - * The user that wants to start the learning process. - * @param project - * The project the learning process runs in. - * @param startConfiguration - * The configuration to use for the learning process. - * @throws IllegalArgumentException - * If the configuration was invalid or the user tried to start a second active learning thread. - * @throws IllegalStateException - * If a learning process is already active. - * @throws NotFoundException - * If the symbols specified in the configuration could not be found. - */ - public LearnerResult start(User user, Project project, LearnerStartConfiguration startConfiguration) { - final var userInDb = this.userDAO.getByID(user.getId()); - checkRunningProcesses(userInDb, project.getId()); - - final var createdResult = transactionTemplate.execute(t -> { - final var setup = startConfiguration.getSetup(); - final var createdSetup = setup.getId() != null ? setup : learnerSetupDAO.create(user, project.getId(), setup); - - final var options = startConfiguration.getOptions(); - if (options.getComment() == null || options.getComment().trim().equals("")) { - options.setComment(createdSetup.getName()); - } - - // create onetime webhook - if (options.getWebhook() != null) { - final var webhook = options.getWebhook(); - webhook.setOnce(true); - this.webhookDAO.create(user, webhook); - } - - final var result = new LearnerResult(); - result.setSetup(createdSetup); - result.setComment(startConfiguration.getOptions().getComment()); - - final var r = learnerResultDAO.create(user, project.getId(), result); - t.flush(); - - return r; - }); - - enqueueLearningProcess( - project.getId(), - new StartingLearnerProcessQueueItem(user.getId(), project.getId(), createdResult.getId()) - ); - - return createdResult; - } - - /** - * Resuming a learning process by activating a LearningThread. - * - * @param user - * The user that wants to restart his latest thread. - * @param projectId - * The project that is learned. - * @param testNo - * The result of a previous process. - * @param configuration - * The configuration to use for the next learning steps. - */ - @Transactional(rollbackFor = Exception.class) - public LearnerResult resume(User user, Long projectId, Long testNo, LearnerResumeConfiguration configuration) { - final var userInDb = this.userDAO.getByID(user.getId()); - checkRunningProcesses(userInDb, projectId); - - configuration.checkConfiguration(); - var result = learnerResultDAO.getByTestNo(user, projectId, testNo); - - if (configuration.getStepNo() > result.getSteps().size()) { - throw new IllegalArgumentException("The step number is not valid."); - } - - if (result.getSteps().get(configuration.getStepNo() - 1).isError()) { - throw new IllegalStateException("You cannot resume from a failed step."); - } - - // reset the status in case it has been aborted before - result = learnerResultDAO.updateStatus(result.getId(), Status.PENDING); - - enqueueLearningProcess( - result.getProjectId(), - new ResumingLearnerProcessQueueItem(user.getId(), result.getProjectId(), result.getId(), configuration) - ); - - return result; - } - - /** - * Starts the thread and updates the thread maps. - * - * @param projectId - * The id of the project. - * @param item - * The thread to start. - */ - private void enqueueLearningProcess(Long projectId, AbstractLearnerProcessQueueItem item) { - if (learnerThreads.containsKey(projectId)) { - learnerThreads.get(projectId).enqueue(item); - } else { - final var thread = applicationContext.getBean(LearnerThread.class); - thread.onFinished(() -> learnerThreads.remove(projectId)); - - learnerThreads.put(projectId, thread); - thread.enqueue(item); - thread.start(); - } - } - - /** - * Ends the learning process after the current step. - * - * @param projectId - * The id of the project that is learned. - */ - @Transactional(rollbackFor = Exception.class) - public void abort(User user, Long projectId, Long resultId) { - final var project = projectDAO.getByID(user, projectId); // access check - - try { - final var result = learnerResultDAO.getByID(user, projectId, resultId); - - final var userIsOwner = project.getOwners().stream() - .map(User::getId) - .anyMatch(ownerId -> ownerId.equals(user.getId())); - - if (!userIsOwner && (result.getExecutedBy() != null && !result.getExecutedBy().equals(user))) { - throw new UnauthorizedException("You are not allowed to abort this learning process."); - } - - if (isActive(projectId)) { - learnerThreads.get(projectId).abort(result.getId()); - } - } catch (NotFoundException e) { - learnerThreads.get(projectId).removeFromProcessQueue(resultId); - } - } - - /** - * Method to check if a learning process is still active or if it has finished. - * - * @param projectId - * The id of the project. - * @return true if the learning process is active, false otherwise. - */ - public boolean isActive(Long projectId) { - return learnerThreads.containsKey(projectId); - } - - @Transactional(rollbackFor = Exception.class) - public boolean hasRunningOrPendingTasks(User user, Long projectId) { - if (!isActive(projectId)) { - return false; - } - - LearnerStatus learnerStatus = this.getStatus(user, projectId); - - List currentProcessSingletonList = Optional.ofNullable(learnerStatus.getCurrentProcess()) - .map(LearningProcessStatus::getResult) - .map(List::of) - .orElse(Collections.emptyList()); - - return Stream.of(currentProcessSingletonList, learnerStatus.getQueue()) - .flatMap(List::stream) - .map(LearnerResult::getStatus) - .anyMatch(status -> status.equals(LearnerResult.Status.IN_PROGRESS) - || status.equals(LearnerResult.Status.PENDING)); - } - - public long getNumberOfUserOwnedLearnProcesses(User user) { - return user.getProjectsOwner().stream() - .map(Project::getId) - .filter(projectId -> hasRunningOrPendingTasks(user, projectId)) - .count(); - } - - /** - * Get the status of the Learner as immutable object. - * - * @param projectId - * The id of the project. - * @return A snapshot of the Learner status. - */ - @Transactional(rollbackFor = Exception.class) - public LearnerStatus getStatus(User user, Long projectId) { - if (isActive(projectId)) { - final var thread = learnerThreads.get(projectId); - final var process = thread.getCurrentProcess(); - - // Make sure that a result has been persisted - if (process.getResult() == null) return new LearnerStatus(); - - final var processStatus = new LearningProcessStatus(); - processStatus.setCurrentQueries(process.getCurrentQueries()); - processStatus.setPhase(process.getLearnerPhase()); - processStatus.setResult(process.getResult()); - - final var counterOracle = process.getCounterOracle(); - if (counterOracle != null) { - processStatus.setCurrentQueryCount(counterOracle.getQueryCount()); - processStatus.setCurrentSymbolCount(counterOracle.getSymbolCount()); - } - - final var status = new LearnerStatus(); - status.setCurrentProcess(processStatus); - - final var results = learnerResultDAO.getByIDs(user, projectId, thread.getProcessQueue().stream() - .map(c -> c.resultId) - .collect(Collectors.toList()) - ); - - status.setQueue(results); - return status; - } else { - return new LearnerStatus(); - } - } - - /** - * Compare two MealyMachines and calculate their separating word. - * - * @param mealy1 - * The first Mealy to compare. - * @param mealy2 - * The second Mealy to compare. - * @return If the machines are different: The corresponding separating word; otherwise: "" - */ - public SeparatingWord separatingWord(CompactMealyMachineProxy mealy1, CompactMealyMachineProxy mealy2) { - final Alphabet alphabet1 = mealy1.createAlphabet(); - final Alphabet alphabet2 = mealy2.createAlphabet(); - checkAlphabetsAreIdentical(alphabet1, alphabet2); - - final CompactMealy mealyMachine1 = mealy1.createMealyMachine(alphabet1); - final CompactMealy mealyMachine2 = mealy2.createMealyMachine(alphabet2); - - final Word separatingWord = Automata.findSeparatingWord(mealyMachine1, mealyMachine2, alphabet1); - - if (separatingWord != null) { - return new SeparatingWord( - separatingWord, - mealyMachine1.computeOutput(separatingWord), - mealyMachine2.computeOutput(separatingWord) - ); - } else { - return new SeparatingWord(); - } - } - - public CompactMealy differenceAutomaton( - final CompactMealyMachineProxy mealyProxy1, - final CompactMealyMachineProxy mealyProxy2 - ) { - final var alphabet1 = mealyProxy1.createAlphabet(); - final var alphabet2 = mealyProxy2.createAlphabet(); - checkAlphabetsAreIdentical(alphabet1, alphabet2); - - final var undefinedOutput = "__"; - final var diffSul = new DifferenceSimulatorSUL( - mealyProxy1.createMealyMachine(alphabet1), - mealyProxy2.createMealyMachine(alphabet2), - undefinedOutput - ); - - final var membershipOracle = new SULOracle<>(diffSul); - - final var learner = new TTTLearnerMealyBuilder() - .withAlphabet(alphabet1) - .withOracle(membershipOracle) - .create(); - - final var equivalenceOracle = new WpMethodEQOracle<>(membershipOracle, 2); - - learner.startLearning(); - - while (true) { - final var hyp = learner.getHypothesisModel(); - final var counterexample = equivalenceOracle.findCounterExample(hyp, alphabet1); - - if (counterexample == null) { - break; - } else { - learner.refineHypothesis(counterexample); - } - } - - final var hyp = learner.getHypothesisModel(); - final var prunedHyp = MealyFilter.pruneTransitionsWithOutput( - hyp, - alphabet1, - undefinedOutput - ); - - return CompactMealyMachineProxy - .createFrom(prunedHyp, alphabet1) - .createMealyMachine(alphabet1); - } - - public CompactMealy differenceTree(User user, Long projectId, DifferenceTreeInput input) { - - final CompactMealy differenceTree; - if (input instanceof DifferenceTreeInput.AutomataInput) { - differenceTree = differenceTree( - ((DifferenceTreeInput.AutomataInput) input).automaton1, - ((DifferenceTreeInput.AutomataInput) input).automaton2, - input.strategy - ); - } else if (input instanceof DifferenceTreeInput.LearnerResultInput) { - - final var result1 = learnerResultDAO.getByTestNo(user, projectId, ((DifferenceTreeInput.LearnerResultInput) input).result1); - final var step1 = result1.getSteps().get(((DifferenceTreeInput.LearnerResultInput) input).step1); - final var result2 = learnerResultDAO.getByTestNo(user, projectId, ((DifferenceTreeInput.LearnerResultInput) input).result2); - final var step2 = result2.getSteps().get(((DifferenceTreeInput.LearnerResultInput) input).step2); - - differenceTree = differenceTree( - result1, - result2, - step1, - step2, - input.strategy - ); - } else { - throw new IllegalArgumentException("Invalid input!"); - } - - return differenceTree; - } - - public CompactMealy differenceTree( - final LearnerResult result1, - final LearnerResult result2, - final LearnerResultStep step1, - final LearnerResultStep step2, - final DifferenceTreeStrategy strategy - ) { - try { - switch (strategy) { - case DISCRIMINATION_TREE: - final var learner1 = result1.getSetup().getAlgorithm().createLearner(step1.getHypothesis().createAlphabet(), null); - result1.getSetup().getAlgorithm().resume(learner1, step1.getState()); - - final var learner2 = result2.getSetup().getAlgorithm().createLearner(step2.getHypothesis().createAlphabet(), null); - result2.getSetup().getAlgorithm().resume(learner2, step2.getState()); - - final var tttLearner1 = (TTTLearnerMealy) learner1; - final var tttLearner2 = (TTTLearnerMealy) learner2; - - final BaseTTTDiscriminationTree> dt1 = tttLearner1.getDiscriminationTree(); - final BaseTTTDiscriminationTree> dt2 = tttLearner2.getDiscriminationTree(); - - final var tests = new ArrayList>(); - generateTestsDt(dt1, tests); - generateTestsDt(dt2, tests); - - final var mealy1 = step1.getHypothesis().createMealyMachine(step1.getHypothesis().createAlphabet()); - final var mealy2 = step2.getHypothesis().createMealyMachine(step2.getHypothesis().createAlphabet()); - - final Set diffs = new HashSet<>(); - tests.forEach(test -> { - final var o1 = mealy1.computeOutput(test); - final var o2 = mealy2.computeOutput(test); - if (!o1.equals(o2)) { - diffs.add(new SeparatingWord(test, o1, o2)); - } - }); - - return buildDifferenceTree(diffs, step1.getHypothesis().createAlphabet()); - default: - return differenceTree( - step1.getHypothesis(), - step2.getHypothesis(), - strategy - ); - } - } catch (Exception e) { - e.printStackTrace(); - throw new IllegalArgumentException(e.getCause()); - } - } - - private void generateTestsDt(BaseTTTDiscriminationTree> dt1, ArrayList> tests) { - for (var e : dt1) { - if (e.isLeaf()) { - Word accessSequence = e.getData().getAccessSequence(); - List testCaseSymbols = new ArrayList<>(); - - var nodeP = e; - while (!(nodeP.isRoot())) { - nodeP = nodeP.getParent(); - var discriminator = nodeP.getDiscriminator(); - testCaseSymbols.addAll(accessSequence.asList()); - testCaseSymbols.addAll(discriminator.asList()); - tests.add(Word.fromList(testCaseSymbols)); - testCaseSymbols.clear(); - } - } else if (e.isRoot() && e.getData() != null) { - tests.add(e.getData().getAccessSequence()); - } - } - } - - /** - * Find differences between two models. - * - * @param mealyProxy1 - * The one model. - * @param mealyProxy2 - * The other model. - * @param strategy - * The strategy - * @return The differences found as a minimized, incomplete mealy machine - */ - public CompactMealy differenceTree( - final CompactMealyMachineProxy mealyProxy1, - final CompactMealyMachineProxy mealyProxy2, - final DifferenceTreeStrategy strategy - ) { - final Alphabet alphabet1 = mealyProxy1.createAlphabet(); - final Alphabet alphabet2 = mealyProxy2.createAlphabet(); - checkAlphabetsAreIdentical(alphabet1, alphabet2); - - final CompactMealy hyp1 = mealyProxy1.createMealyMachine(alphabet1); - final CompactMealy hyp2 = mealyProxy2.createMealyMachine(alphabet1); - - // the words where the output differs - final Set diffs = new HashSet<>(); - findDifferences(hyp1, hyp2, alphabet1, diffs, strategy); - findDifferences(hyp2, hyp1, alphabet1, diffs, strategy); - - return buildDifferenceTree(diffs, alphabet1); - } - - private CompactMealy buildDifferenceTree(Set diffs, Alphabet alphabet) { - // build tree - // the tree is organized as an incomplete mealy machine - final CompactMealy diffTree = new CompactMealy<>(alphabet); - diffTree.addInitialState(); - - for (final SeparatingWord diff : diffs) { - int currentState = diffTree.getInitialState(); - - for (int k = 0; k < diff.getInput().length(); k++) { - final String sym = diff.getInput().getSymbol(k); - - if (diffTree.getTransition(currentState, sym) == null) { - // if the transition does not yet exist in the tree - // create a new state in the tree and add the same transition - final int newState = diffTree.addState(); - - String out = diff.getOutput2().getSymbol(k); - if (k == diff.getInput().length() - 1) { - out += " <-> " + diff.getOutput1().getSymbol(k); - } - - diffTree.addTransition(currentState, sym, newState, out); - - // update the current state of the tree to the newly created one - currentState = newState; - } else { - // update the current state of the tree accordingly - currentState = diffTree.getTransition(currentState, sym).getSuccId(); - } - } - } - - // minimize the tree - final CompactMealy target = new CompactMealy<>(alphabet); - Automata.minimize(diffTree, alphabet, target); - - return target; - } - - /** - * Tests all words from the w method from mealyProxy1 on mealyProxy2. Words with a - * different output are added to the difference. - * - * @param hyp1 - * The hypothesis to test the tests on. - * @param hyp2 - * The hypothesis to generate the w-method tests from. - * @param alphabet - * The alphabet. - * @param diffs - * The set of words that have a different output. - */ - private void findDifferences( - final CompactMealy hyp1, - final CompactMealy hyp2, - final Alphabet alphabet, - final Set diffs, - final DifferenceTreeStrategy strategy - ) { - final Iterator> testsIterator; - if (Objects.requireNonNull(strategy) == DifferenceTreeStrategy.W_METHOD) { - testsIterator = new WMethodTestsIterator<>(hyp2, alphabet, 0); - } else { - testsIterator = new WpMethodTestsIterator<>(hyp2, alphabet, 0); - } - - while (testsIterator.hasNext()) { - final Word word = testsIterator.next(); - - final Word out1 = hyp1.computeOutput(word); - final Word out2 = hyp2.computeOutput(word); - - if (!out1.equals(out2)) { - for (int i = 0; i < word.length(); i++) { - if (!out1.getSymbol(i).equals(out2.getSymbol(i))) { - diffs.add(new SeparatingWord(word.subWord(0, i + 1), out1, out2)); - break; - } - } - } - } - } - - private void checkRunningProcesses(User user, Long projectId) { - final var numberOfCurrentProcesses = getNumberOfUserOwnedLearnProcesses(user) - + testService.getNumberOfUserOwnedTestProcesses(user); - - if (numberOfCurrentProcesses >= user.getMaxAllowedProcesses()) { - // check if there are already running/pending tests in this project - if (!this.hasRunningOrPendingTasks(user, projectId)) { - throw new ResourcesExhaustedException("You are not allowed to have more than " - + user.getMaxAllowedProcesses() - + " concurrent test/learn processes."); - } - } - } - - private void checkAlphabetsAreIdentical(Alphabet a1, Alphabet a2) { - if (a1.size() != a2.size() || !a1.containsAll(a2)) { - throw new IllegalArgumentException("The alphabets of the hypotheses are not identical."); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/LearnerThread.java b/backend/src/main/java/de/learnlib/alex/learning/services/LearnerThread.java deleted file mode 100644 index 8eb6feb15..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/LearnerThread.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Deque; -import java.util.List; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Service; - -/** - * A learner thread runs learning processes per project and handles the process queue. - */ -@Service -@Scope("prototype") -public class LearnerThread extends Thread { - - /** - * Listener that is called as soon as the queue is empty and the current learner process is terminated. - */ - public interface FinishedListener { - void handleFinished(); - } - - @Autowired - private ApplicationContext applicationContext; - - private FinishedListener finishedListener; - - public void onFinished(FinishedListener listener) { - this.finishedListener = listener; - } - - /** The FIFO queue for learning processes. */ - private final Deque processQueue = new ArrayDeque<>(); - - /** The process that is currently being executed. */ - private AbstractLearnerProcess currentProcess; - - public void enqueue(AbstractLearnerProcessQueueItem item) { - this.processQueue.offer(item); - } - - public void abort(Long resultId) { - if (currentProcess != null) { - while (!currentProcess.isInitialized()) { - try { - Thread.sleep(100); - } catch (Exception ignored) { - } - } - - if (currentProcess.getResult().getId().equals(resultId)) { - this.currentProcess.abort(); - } - } - } - - public void removeFromProcessQueue(Long resultId) { - processQueue.removeIf(i -> i.resultId.equals(resultId)); - } - - @Override - public void run() { - while (!processQueue.isEmpty()) { - - final var item = processQueue.poll(); - - if (item instanceof StartingLearnerProcessQueueItem) { - currentProcess = applicationContext.getBean(StartingLearnerProcess.class); - ((StartingLearnerProcess) currentProcess).init((StartingLearnerProcessQueueItem) item); - } else if (item instanceof ResumingLearnerProcessQueueItem) { - currentProcess = applicationContext.getBean(ResumingLearnerProcess.class); - ((ResumingLearnerProcess) currentProcess).init((ResumingLearnerProcessQueueItem) item); - } - - if (currentProcess.isAbortedOrHasFailed()) { - continue; - } - - currentProcess.run(); - } - - this.finishedListener.handleFinished(); - } - - public AbstractLearnerProcess getCurrentProcess() { - return currentProcess; - } - - public List getProcessQueue() { - return new ArrayList<>(processQueue); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/ModelExporter.java b/backend/src/main/java/de/learnlib/alex/learning/services/ModelExporter.java deleted file mode 100644 index 3c2dba074..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/ModelExporter.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.learning.dao.LearnerResultDAO; -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.learning.entities.LearnerResultStep; -import java.io.IOException; -import java.io.StringWriter; -import javax.validation.ValidationException; -import net.automatalib.automata.transducers.MealyMachine; -import net.automatalib.serialization.dot.GraphDOT; -import net.automatalib.words.Alphabet; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(rollbackFor = Exception.class, readOnly = true) -public class ModelExporter { - - private final LearnerResultDAO learnerResultDAO; - - @Autowired - public ModelExporter(LearnerResultDAO learnerResultDAO) { - this.learnerResultDAO = learnerResultDAO; - } - - public String exportDot(User user, Long projectId, Long testNo, Long stepNo) { - final LearnerResult learnerResult = learnerResultDAO.getByTestNo(user, projectId, testNo); - - final LearnerResultStep step = learnerResult.getSteps().stream() - .filter(s -> s.getStepNo().equals(stepNo)) - .findFirst() - .orElseThrow(() -> new NotFoundException("The step could not be found.")); - - final Alphabet alphabet = step.getHypothesis().createAlphabet(); - final MealyMachine mealy = step.getHypothesis().createMealyMachine(alphabet); - - try { - final StringWriter sw = new StringWriter(); - GraphDOT.write(mealy, alphabet, sw); - return sw.toString(); - } catch (IOException e) { - throw new ValidationException("Could not write DOT file"); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/ResumingLearnerProcess.java b/backend/src/main/java/de/learnlib/alex/learning/services/ResumingLearnerProcess.java deleted file mode 100644 index 6526765d5..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/ResumingLearnerProcess.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services; - -import de.learnlib.alex.auth.dao.UserDAO; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.dao.SymbolDAO; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.learning.dao.LearnerResultDAO; -import de.learnlib.alex.learning.dao.LearnerResultStepDAO; -import de.learnlib.alex.learning.dao.LearnerSetupDAO; -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.learning.entities.LearnerResultStep; -import de.learnlib.alex.learning.entities.LearnerResumeConfiguration; -import de.learnlib.alex.learning.entities.ReadOutputConfig; -import de.learnlib.alex.learning.entities.Statistics; -import de.learnlib.alex.learning.entities.learnlibproxies.CompactMealyMachineProxy; -import de.learnlib.alex.learning.entities.learnlibproxies.eqproxies.SampleEQOracleProxy; -import de.learnlib.alex.learning.events.LearnerEvent; -import de.learnlib.alex.learning.services.connectors.PreparedConnectorContextHandlerFactory; -import de.learnlib.alex.modelchecking.services.ModelCheckerService; -import de.learnlib.alex.testing.dao.TestDAO; -import de.learnlib.alex.webhooks.services.WebhookService; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; -import net.automatalib.SupportsGrowingAlphabet; -import org.apache.logging.log4j.ThreadContext; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Service; -import org.springframework.transaction.support.TransactionTemplate; - -/** The learner thread that is used for resuming an old experiment from a given step. */ -@Service -@Scope("prototype") -public class ResumingLearnerProcess extends AbstractLearnerProcess { - - private final SymbolDAO symbolDAO; - - private final SULUtilsService sulUtils; - - private LearnerResumeConfiguration resumeConfiguration; - - @Autowired - public ResumingLearnerProcess( - UserDAO userDAO, - ProjectDAO projectDAO, - LearnerResultDAO learnerResultDAO, - LearnerSetupDAO learnerSetupDAO, - LearnerResultStepDAO learnerResultStepDAO, - TestDAO testDAO, - WebhookService webhookService, - PreparedConnectorContextHandlerFactory contextHandlerFactory, - TransactionTemplate transactionTemplate, - SymbolDAO symbolDAO, - ModelCheckerService modelCheckerService, - SULUtilsService sulUtils - ) { - super( - userDAO, - projectDAO, - learnerResultDAO, - learnerSetupDAO, - learnerResultStepDAO, - testDAO, - webhookService, - contextHandlerFactory, - transactionTemplate, - modelCheckerService - ); - this.symbolDAO = symbolDAO; - this.sulUtils = sulUtils; - } - - @Override - void init(ResumingLearnerProcessQueueItem context) { - transactionTemplate.execute(t -> { - initInternal(context); - resumeConfiguration = context.configuration; - setEquivalenceOracle(resumeConfiguration.getEqOracle()); - removeSteps(); - return null; - }); - } - - private void removeSteps() { - // remove all steps after the one where the learning process should be continued from - if (result.getSteps().size() > 0) { - final var stepsToRemove = result.getSteps().stream() - .filter(s -> s.getStepNo() > resumeConfiguration.getStepNo()) - .collect(Collectors.toList()); - - if (stepsToRemove.size() > 0) { - result = learnerResultDAO.removeSteps(result.getId(), stepsToRemove); - - // since we allow alphabets to grow, set the alphabet to the one of the latest hypothesis - final var alphabet = result.getSteps() - .get(result.getSteps().size() - 1) - .getHypothesis() - .createAlphabet(); - - final var symbolsToRemove = setup.getSymbols().stream() - .filter(s -> !alphabet.contains(s.getAliasOrComputedName())) - .collect(Collectors.toList()); - - setup = learnerSetupDAO.removeSymbols(setup.getId(), symbolsToRemove); - } - - // add the new alphabet symbols to the config. - if (resumeConfiguration.getSymbolsToAdd().size() > 0) { - final var symbolMap = new HashMap(); - symbolDAO.getByIds(user, project.getId(), resumeConfiguration.getSymbolIds()) - .forEach(s -> symbolMap.put(s.getId(), s)); - resumeConfiguration.getSymbolsToAdd().forEach(ps -> ps.setSymbol(symbolMap.get(ps.getSymbol().getId()))); - } - } - } - - @Override - public void run() { - ThreadContext.put("userId", String.valueOf(user.getId())); - logger.info(LoggerMarkers.LEARNER, "Resuming a learner thread."); - - try { - resumeLearning(); - shutdown(); - } catch (Exception e) { - logger.error(LoggerMarkers.LEARNER, "Something in the LearnerThread while resuming went wrong:", e); - e.printStackTrace(); - shutdownWithErrors(e.getMessage()); - } finally { - logger.info(LoggerMarkers.LEARNER, "The learner finished resuming the experiment."); - ThreadContext.remove("userId"); - } - } - - private void resumeLearning() throws Exception { - result = learnerResultDAO.updateStatus(result.getId(), LearnerResult.Status.IN_PROGRESS); - - // initialize learner from old state - final byte[] learnerState = result.getSteps().get(result.getSteps().size() - 1).getState(); - setup.getAlgorithm().resume(learner, learnerState); - - if (resumeConfiguration.getEqOracle() instanceof SampleEQOracleProxy) { - validateCounterexample(user, result, resumeConfiguration); - } - - if (resumeConfiguration.getSymbolsToAdd().size() > 0 && learner instanceof SupportsGrowingAlphabet) { - final SupportsGrowingAlphabet growingAlphabetLearner = (SupportsGrowingAlphabet) learner; - for (final ParameterizedSymbol symbol : resumeConfiguration.getSymbolsToAdd()) { - - // update setup with new symbol - setup = learnerSetupDAO.addSymbols(setup.getId(), List.of(symbol)); - - // make symbol available to symbol mapper - symbolMapper.addSymbol(symbol); - - // extend instance of the alphabet - abstractAlphabet.add(symbol.getAliasOrComputedName()); - - // if the cache is not reinitialized with the new alphabet, we will get cache errors later - if (setup.isEnableCache() && cacheOracle != null) { - cacheOracle.addAlphabetSymbol(symbol.getAliasOrComputedName()); - } - - // measure how much time and membership queries it takes to add the symbol - final long addSymbolStartTime = System.currentTimeMillis(); - growingAlphabetLearner.addAlphabetSymbol(symbol.getAliasOrComputedName()); - final long addSymbolEndTime = System.currentTimeMillis(); - - final Statistics statistics = new Statistics(); - statistics.getDuration().setLearner(addSymbolEndTime - addSymbolStartTime); - statistics.getMqsUsed().setLearner(counterOracle.getQueryCount()); - statistics.getSymbolsUsed().setLearner(counterOracle.getSymbolCount()); - counterOracle.reset(); - - final LearnerResultStep step = new LearnerResultStep(); - step.setHypothesis(CompactMealyMachineProxy.createFrom(learner.getHypothesisModel(), abstractAlphabet)); - step.setState(setup.getAlgorithm().suspend(learner)); - step.setAlgorithmInformation(setup.getAlgorithm().getInternalData(learner)); - step.setEqOracle(equivalenceOracleProxy); - step.setStatistics(statistics); - result = learnerResultDAO.addStep(result.getId(), step); - - startLearningLoop(); - } - } else { - startLearningLoop(); - } - - webhookService.fireEvent(user, new LearnerEvent.Finished(result)); - } - - private void validateCounterexample(User user, LearnerResult result, LearnerResumeConfiguration configuration) - throws IllegalArgumentException { - - final SampleEQOracleProxy oracle = (SampleEQOracleProxy) configuration.getEqOracle(); - for (List counterexample : oracle.getCounterExamples()) { - List symbolsFromCounterexample = new ArrayList<>(); - List outputs = new ArrayList<>(); - - // search symbols in configuration where symbol.name == counterexample.input - for (SampleEQOracleProxy.InputOutputPair io : counterexample) { - Optional symbol = result.getSetup().getSymbols().stream() - .filter(s -> s.getAliasOrComputedName().equals(io.getInput())) - .findFirst(); - - // collect all outputs in order to compare it with the result of learner.getSystemOutputs() - if (symbol.isPresent()) { - symbolsFromCounterexample.add(symbol.get()); - outputs.add(io.getOutput()); - } else { - throw new IllegalArgumentException("The symbol with the name '" + io.getInput() + "'" - + " is not used in this test setup."); - } - } - - final ReadOutputConfig config = new ReadOutputConfig( - result.getSetup().getPreSymbol(), - symbolsFromCounterexample, - result.getSetup().getPostSymbol(), - result.getSetup().getWebDriver() - ); - - // check if the given sample matches the behavior of the SUL - final List results = sulUtils.getSystemOutputs( - user, - result.getProject(), - result.getSetup().getEnvironments().get(0), - config - ).stream() - .map(ExecuteResult::getOutput) - .toList(); - - if (!results.equals(outputs)) { - throw new IllegalArgumentException("At least one of the given samples for counterexamples" - + " is not matching the behavior of the SUL."); - } - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/ResumingLearnerProcessQueueItem.java b/backend/src/main/java/de/learnlib/alex/learning/services/ResumingLearnerProcessQueueItem.java deleted file mode 100644 index 5de365dc4..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/ResumingLearnerProcessQueueItem.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services; - -import de.learnlib.alex.learning.entities.LearnerResumeConfiguration; - -public class ResumingLearnerProcessQueueItem extends AbstractLearnerProcessQueueItem { - - public LearnerResumeConfiguration configuration; - - public ResumingLearnerProcessQueueItem(Long userId, Long projectId, Long resultId, LearnerResumeConfiguration configuration) { - super(userId, projectId, resultId); - this.configuration = configuration; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/SULUtilsService.java b/backend/src/main/java/de/learnlib/alex/learning/services/SULUtilsService.java deleted file mode 100644 index ede631d82..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/SULUtilsService.java +++ /dev/null @@ -1,66 +0,0 @@ -package de.learnlib.alex.learning.services; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.learning.entities.ReadOutputConfig; -import de.learnlib.alex.learning.exceptions.LearnerException; -import de.learnlib.alex.learning.services.connectors.PreparedConnectorContextHandlerFactory; -import java.util.List; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -public class SULUtilsService { - - private final PreparedConnectorContextHandlerFactory contextHandlerFactory; - - @Autowired - public SULUtilsService(PreparedConnectorContextHandlerFactory contextHandlerFactory) { - this.contextHandlerFactory = contextHandlerFactory; - } - - /** - * Determine the output of the SUL by testing a sequence of input symbols. - * - * @param user - * The current user. - * @param project - * The project. - * @param readOutputConfig - * The config to use. - * @return The outputs of the SUL. - */ - @Transactional(rollbackFor = Exception.class) - public List getSystemOutputs( - User user, - Project project, - ProjectEnvironment environment, - ReadOutputConfig readOutputConfig - ) { - final var ctxHandler = contextHandlerFactory.createPreparedContextHandler( - user, - project, - readOutputConfig.getDriverConfig(), - readOutputConfig.getPreSymbol(), - readOutputConfig.getPostSymbol() - ); - final var connectors = ctxHandler.create(environment).createContext(); - - try { - final var outputs = readOutputConfig.getSymbols().stream() - .map(s -> s.execute(connectors)) - .toList(); - connectors.dispose(); - connectors.post(); - return outputs; - } catch (Exception e) { - connectors.dispose(); - connectors.post(); - - throw new LearnerException("Could not read the outputs", e); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/StartingLearnerProcess.java b/backend/src/main/java/de/learnlib/alex/learning/services/StartingLearnerProcess.java deleted file mode 100644 index 5523768a8..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/StartingLearnerProcess.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services; - -import de.learnlib.alex.auth.dao.UserDAO; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.learning.dao.LearnerResultDAO; -import de.learnlib.alex.learning.dao.LearnerResultStepDAO; -import de.learnlib.alex.learning.dao.LearnerSetupDAO; -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.learning.events.LearnerEvent; -import de.learnlib.alex.learning.services.connectors.PreparedConnectorContextHandlerFactory; -import de.learnlib.alex.modelchecking.services.ModelCheckerService; -import de.learnlib.alex.testing.dao.TestDAO; -import de.learnlib.alex.webhooks.services.WebhookService; -import org.apache.logging.log4j.ThreadContext; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Service; -import org.springframework.transaction.support.TransactionTemplate; - -/** The learner thread that is used for starting a new experiment. */ -@Service -@Scope("prototype") -public class StartingLearnerProcess extends AbstractLearnerProcess { - - @Autowired - public StartingLearnerProcess( - UserDAO userDAO, - ProjectDAO projectDAO, - LearnerResultDAO learnerResultDAO, - LearnerSetupDAO learnerSetupDAO, - LearnerResultStepDAO learnerResultStepDAO, - TestDAO testDAO, - WebhookService webhookService, - PreparedConnectorContextHandlerFactory contextHandlerFactory, - TransactionTemplate transactionTemplate, - ModelCheckerService modelCheckerService - ) { - super( - userDAO, - projectDAO, - learnerResultDAO, - learnerSetupDAO, - learnerResultStepDAO, - testDAO, - webhookService, - contextHandlerFactory, - transactionTemplate, - modelCheckerService - ); - } - - @Override - void init(StartingLearnerProcessQueueItem context) { - initInternal(context); - setEquivalenceOracle(result.getSetup().getEquivalenceOracle()); - } - - @Override - public void run() { - ThreadContext.put("userId", String.valueOf(user.getId())); - logger.info(LoggerMarkers.LEARNER, "Started a new learner thread."); - - try { - learn(); - shutdown(); - } catch (Exception e) { - logger.error(LoggerMarkers.LEARNER, "Something in the LearnerThread went wrong:", e); - e.printStackTrace(); - shutdownWithErrors(e.getMessage()); - } finally { - logger.info(LoggerMarkers.LEARNER, "The learner thread has finished."); - ThreadContext.remove("userId"); - } - } - - private void learn() { - result = learnerResultDAO.updateStatus(result.getId(), LearnerResult.Status.IN_PROGRESS); - - learnerPhase = LearnerService.LearnerPhase.LEARNING; - final long learnerStartTime = System.currentTimeMillis(); - learner.startLearning(); - final long learnerEndTime = System.currentTimeMillis(); - - createStep(learnerEndTime, learnerStartTime); - startLearningLoop(); - - webhookService.fireEvent(user, new LearnerEvent.Finished(result)); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/StartingLearnerProcessQueueItem.java b/backend/src/main/java/de/learnlib/alex/learning/services/StartingLearnerProcessQueueItem.java deleted file mode 100644 index 92dd60719..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/StartingLearnerProcessQueueItem.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services; - -public class StartingLearnerProcessQueueItem extends AbstractLearnerProcessQueueItem { - - public StartingLearnerProcessQueueItem(Long userId, Long projectId, Long resultId) { - super(userId, projectId, resultId); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/SymbolMapper.java b/backend/src/main/java/de/learnlib/alex/learning/services/SymbolMapper.java deleted file mode 100644 index 50ab3c370..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/SymbolMapper.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services; - -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.api.exception.SULException; -import de.learnlib.mapper.api.ContextExecutableInput; -import de.learnlib.mapper.api.SULMapper; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class to map the Symbols and their result to the values used in the learning process. - */ -public class SymbolMapper implements SULMapper< - String, - String, - ContextExecutableInput, - ExecuteResult> { - - private static final Logger logger = LoggerFactory.getLogger(SymbolMapper.class); - - /** Map to manage the symbols according to their name in the Alphabet. */ - private final Map symbolMap; - - /** - * Constructor. Initialize the map name -> symbol. - * - * @param symbols - * The symbols for the learning process. - */ - public SymbolMapper(List symbols) { - this.symbolMap = symbols.stream() - .collect(Collectors.toMap(ParameterizedSymbol::getAliasOrComputedName, Function.identity())); - } - - /** - * Private constructor for the {@link #fork()} method. Ensures that an existing symbol map is passed by reference - * and therefore shared across multiple threads. This allows to use a single (global) symbol map across multiple - * forked SULs, which only access the data in a read-only manner. Currently there exists no possibility to modify - * the symbol map concurrently, so we should be safe. - * - * @param symbolMap - * Reference of the original symbolMap. - */ - private SymbolMapper(Map symbolMap) { - this.symbolMap = symbolMap; - } - - /** - * Adds a new symbol to the mapper. - * - * @param symbol - * The symbol to add. - */ - public void addSymbol(ParameterizedSymbol symbol) { - this.symbolMap.putIfAbsent(symbol.getAliasOrComputedName(), symbol); - } - - @Override - public ContextExecutableInput mapInput(String abstractInput) { - return symbolMap.get(abstractInput); - } - - @Override - public String mapOutput(ExecuteResult result) { - return result.getOutput(); - } - - @Override - public MappedException mapUnwrappedException(RuntimeException e) throws RuntimeException { - logger.info("mapper mapped unwrapped exception", e); - return null; - } - - @Override - public MappedException mapWrappedException(SULException e) throws SULException { - logger.info("mapper mapped wrapped exception", e); - return null; - } - - @Override - public void post() { - } - - @Override - public void pre() { - } - - @Override - public boolean canFork() { - return true; - } - - @Nonnull - @Override - public SULMapper, ExecuteResult> fork() - throws UnsupportedOperationException { - return new SymbolMapper(symbolMap); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/TestGenerator.java b/backend/src/main/java/de/learnlib/alex/learning/services/TestGenerator.java deleted file mode 100644 index 714c50ebc..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/TestGenerator.java +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.learning.dao.LearnerResultDAO; -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.learning.entities.LearnerResultStep; -import de.learnlib.alex.learning.entities.TestSuiteGenerationConfig; -import de.learnlib.alex.learning.entities.algorithms.AbstractLearningAlgorithm; -import de.learnlib.alex.testing.dao.TestDAO; -import de.learnlib.alex.testing.entities.Test; -import de.learnlib.alex.testing.entities.TestCase; -import de.learnlib.alex.testing.entities.TestCaseStep; -import de.learnlib.alex.testing.entities.TestSuite; -import de.learnlib.algorithms.discriminationtree.hypothesis.HState; -import de.learnlib.algorithms.discriminationtree.mealy.DTLearnerMealy; -import de.learnlib.algorithms.ttt.base.BaseTTTDiscriminationTree; -import de.learnlib.algorithms.ttt.base.TTTState; -import de.learnlib.algorithms.ttt.mealy.TTTLearnerMealy; -import de.learnlib.api.algorithm.LearningAlgorithm; -import de.learnlib.datastructure.discriminationtree.model.AbstractDTNode; -import de.learnlib.datastructure.discriminationtree.model.AbstractDiscriminationTree; -import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDiscriminationTree; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import javax.validation.ValidationException; -import net.automatalib.automata.transducers.MealyMachine; -import net.automatalib.util.automata.Automata; -import net.automatalib.util.automata.conformance.WMethodTestsIterator; -import net.automatalib.util.automata.conformance.WpMethodTestsIterator; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -/** - * Generate a test suite from a discrimination tree in a learner results. Credits to Philipp Koch. - */ -@Service -public class TestGenerator { - - private final LearnerResultDAO learnerResultDAO; - private final ProjectDAO projectDAO; - private final TestDAO testDAO; - - @Autowired - public TestGenerator(LearnerResultDAO learnerResultDAO, - TestDAO testDAO, - ProjectDAO projectDAO) { - this.learnerResultDAO = learnerResultDAO; - this.testDAO = testDAO; - this.projectDAO = projectDAO; - } - - /** - * Generate a test suite from the discrimination tree of a learner result. - * - * @param user - * The user. - * @param projectId - * The ID of the project. - * @param testNo - * The number of the learning experiment to generate the test suite from. - * @param config - * The configuration object. - * @return The generated test suite. - * @throws NotFoundException - * If one of the entities could not be found. - * @throws IOException - * If a learner state could not be deserialized. - * @throws ClassNotFoundException - * If the learner state could not be cast to the correct class. - */ - @Transactional(rollbackFor = Exception.class) - public TestSuite generate(User user, Long projectId, Long testNo, TestSuiteGenerationConfig config) - throws NotFoundException, IOException, ClassNotFoundException { - - final LearnerResult result = learnerResultDAO.getByTestNo(user, projectId, testNo); - final LearnerResultStep step = result.getSteps().stream() - .filter(s -> s.getStepNo().equals(config.getStepNo())) - .findFirst() - .orElseThrow(() -> new NotFoundException("The step number could not be found.")); - - // Restore the state of the learner so that one can access the discrimination tree. - // Leave the mq oracle null since we don't want to continue learning. - final Alphabet alphabet = step.getHypothesis().createAlphabet(); - final AbstractLearningAlgorithm algorithm = result.getSetup().getAlgorithm(); - final LearningAlgorithm.MealyLearner learner = algorithm.createLearner(alphabet, null); - algorithm.resume(learner, step.getState()); - - final Project project = projectDAO.getByID(user, projectId); - - final TestSuite testSuite; - if (config.getTestSuiteToUpdateId() == null) { - // create the new test suite - final TestSuite generatedTestSuite = new TestSuite(); - generatedTestSuite.setName(config.getName()); - generatedTestSuite.setProject(project); - testSuite = (TestSuite) testDAO.create(user, projectId, generatedTestSuite); - } else { - final TestSuite ts = (TestSuite) testDAO.get(user, projectId, config.getTestSuiteToUpdateId()); - final List testIdsToDelete = ts.getTests().stream() - .filter(t -> t instanceof TestCase && ((TestCase) t).isGenerated()) - .map(Test::getId) - .collect(Collectors.toList()); - testDAO.delete(user, projectId, testIdsToDelete); - testSuite = (TestSuite) testDAO.get(user, projectId, ts.getId()); - } - - final List generatedTestCases = new ArrayList<>(); - - final Function testCaseFn = (n) -> _createTestCase(user, project, testSuite, n); - - switch (config.getMethod()) { - case DT: - if (learner instanceof TTTLearnerMealy) { - final TTTLearnerMealy tttLearner = (TTTLearnerMealy) learner; - final BaseTTTDiscriminationTree> tree = tttLearner.getDiscriminationTree(); - computeTestCasesDt(testCaseFn, tree, TTTState::getAccessSequence, (as) -> step.getHypothesis().createMealyMachine(alphabet).computeOutput(as), - Function.identity(), Function.identity(), result, generatedTestCases); - } else if (learner instanceof DTLearnerMealy) { - final DTLearnerMealy dtLearner = (DTLearnerMealy) learner; - final AbstractWordBasedDiscriminationTree, HState, Void, String>> - dtree = dtLearner.getDiscriminationTree(); - computeTestCasesDt(testCaseFn, dtree, HState::getAccessSequence, (as) -> dtLearner.getHypothesisModel().computeOutput(as), - Function.identity(), Function.identity(), result, generatedTestCases); - } else { - throw new ValidationException("Can only generate test suites for TTT and DT algorithm."); - } - break; - case W_METHOD: - computeTestCasesWMethod(testCaseFn, learner.getHypothesisModel(), result, new WMethodTestsIterator<>(learner.getHypothesisModel(), result.getSetup().getSigma(), 0), generatedTestCases); - break; - case WP_METHOD: - computeTestCasesWMethod(testCaseFn, learner.getHypothesisModel(), result, new WpMethodTestsIterator<>(learner.getHypothesisModel(), result.getSetup().getSigma(), 0), generatedTestCases); - break; - case TRANS_COVER: - computeTestCasesTransCover(testCaseFn, learner.getHypothesisModel(), result, alphabet, generatedTestCases); - default: - break; - } - - for (TestCase tc : testSuite.getTestCases()) { - testDAO.update(user, project.getId(), tc.getId(), tc); - } - - return testSuite; - } - - private void computeTestCasesWMethod(Function createTestCaseFn, - MealyMachine hypothesis, - LearnerResult lr, Iterator> testsIterator, - List generatedTestCases) throws NotFoundException { - int testNum = 0; - while (testsIterator.hasNext()) { - final Word word = testsIterator.next(); - final List pSymbolIds = convertWordToPSymbolIds(word, lr.getSetup().getSymbols()); - final TestCase testCase = createTestCaseFn.apply(String.valueOf(testNum++)); - setTestCaseSteps(testCase, lr, pSymbolIds, hypothesis.computeOutput(word), generatedTestCases); - } - } - - private void computeTestCasesTransCover(Function createTestCaseFn, - MealyMachine hypothesis, - LearnerResult lr, Alphabet alphabet, - List generatedTestCases) - throws NotFoundException { - - int testNum = 0; - for (Word word : Automata.transitionCover(hypothesis, alphabet)) { - final List pSymbolIds = convertWordToPSymbolIds(word, lr.getSetup().getSymbols()); - final TestCase testCase = createTestCaseFn.apply(String.valueOf(testNum++)); - setTestCaseSteps(testCase, lr, pSymbolIds, hypothesis.computeOutput(word), generatedTestCases); - } - } - - private > void computeTestCasesDt( - Function createTestCaseFn, - AbstractDiscriminationTree tree, - Function> accessSequenceExtractor, - Function, Word> asTransformer, - Function> dscrExtractor, - Function> outputExtractor, - LearnerResult lr, List generatedTestCases) - throws NotFoundException { - - int i = 0; - - for (N e : tree) { - if (e.isLeaf()) { - Word accessSequence = accessSequenceExtractor.apply(e.getData()); - Word accessSequenceOutcome = asTransformer.apply(accessSequence); - - List accessSequenceAsIds = - new ArrayList<>(convertWordToPSymbolIds(accessSequence, lr.getSetup().getSymbols())); - List outcomeList = new ArrayList<>(); - List testCaseSymbols = new ArrayList<>(); - - N nodeP = e; - - while (!(nodeP.isRoot())) { - outcomeList.addAll(convertWordToStringList(accessSequenceOutcome)); - Word inEdge = outputExtractor.apply(nodeP.getParentOutcome()); - - nodeP = nodeP.getParent(); - - DSCR discriminator = nodeP.getDiscriminator(); - testCaseSymbols.addAll(accessSequenceAsIds); - testCaseSymbols.addAll(convertWordToPSymbolIds(dscrExtractor.apply(discriminator), lr.getSetup().getSymbols())); - - final TestCase testCase = createTestCaseFn.apply(String.valueOf(i++)); - - outcomeList.addAll(convertWordToStringList(inEdge)); - setTestCaseSteps(testCase, lr, testCaseSymbols, Word.fromList(outcomeList), generatedTestCases); - - outcomeList.clear(); - testCaseSymbols.clear(); - } - - accessSequenceAsIds.clear(); - } else if (e.isRoot() && e.getData() != null) { - final List accessSequenceAsList = - convertWordToPSymbolIds(accessSequenceExtractor.apply(e.getData()), lr.getSetup().getSymbols()); - - final TestCase testCase = createTestCaseFn.apply(String.valueOf(i++)); - setTestCaseSteps(testCase, lr, accessSequenceAsList, Word.epsilon(), generatedTestCases); - accessSequenceAsList.clear(); - } - } - } - - private TestCase _createTestCase(User user, Project project, TestSuite parent, String name) { - final TestCase tc = new TestCase(); - tc.setProject(project); - tc.setName(name); - tc.setParent(parent); - tc.setGenerated(true); - return (TestCase) testDAO.create(user, project.getId(), tc); - } - - private void setTestCaseSteps(TestCase testCase, LearnerResult lr, List pSymbolIds, - Word outputs, List generatedTestCases) - throws NotFoundException { - setSteps(lr.getSetup().getPreSymbol(), testCase, testCase.getPreSteps()); - setStepsByPSymbolIds(lr, testCase, pSymbolIds); - setSteps(lr.getSetup().getPostSymbol(), testCase, testCase.getPostSteps()); - - for (int i = 0; i < outputs.size(); i++) { - final TestCaseStep step = testCase.getSteps().get(i); - final String sym = outputs.getSymbol(i); - step.setExpectedOutputSuccess(sym.startsWith(ExecuteResult.DEFAULT_SUCCESS_OUTPUT)); - step.setExpectedOutputMessage(getExpectedOutputMessage(sym)); - } - - generatedTestCases.add(testCase); - } - - private String getExpectedOutputMessage(String output) { - final Pattern p = Pattern.compile("^(Ok | Failed )\\((.*?)\\)$"); - final Matcher m = p.matcher(output); - return m.matches() ? m.group(2) : ""; - } - - private void setSteps(ParameterizedSymbol pSymbol, TestCase testCase, List stepList) { - if (pSymbol != null) { // It can be that e.g. the post symbol has not been used - final TestCaseStep step = new TestCaseStep(); - step.setTestCase(testCase); - step.setPSymbol(pSymbol.copy()); - stepList.add(step); - } - } - - private void setStepsByPSymbolIds(LearnerResult result, TestCase testCase, List pSymbolIds) throws NotFoundException { - final Map pSymbolMap = result.getSetup().getSymbols().stream() - .collect(Collectors.toMap(ParameterizedSymbol::getId, Function.identity())); - - for (Long id : pSymbolIds) { - setSteps(pSymbolMap.get(id), testCase, testCase.getSteps()); - } - } - - private List convertWordToStringList(Word word) { - return word.stream().collect(Collectors.toList()); - } - - private List convertWordToPSymbolIds(Word word, List pSymbols) { - final Map symbolMap = pSymbols.stream() - .collect(Collectors.toMap(ParameterizedSymbol::getAliasOrComputedName, Function.identity())); - - return word.stream().map(symbol -> symbolMap.get(symbol).getId()).collect(Collectors.toList()); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/connectors/Connector.java b/backend/src/main/java/de/learnlib/alex/learning/services/connectors/Connector.java deleted file mode 100644 index f9a43ef20..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/connectors/Connector.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services.connectors; - -/** - * Interface that describes the basics of a Connector. - */ -public interface Connector { - - /** - * Method called during the reset of the SUL. - * Set the connector back to the initial state. - * - * @throws Exception - * If an exception occurred while the reset. - */ - void reset() throws Exception; - - /** - * Method that is called after a membership query has been executed. - */ - void dispose(); - - /** - * Method that should be called after the learning that allows to do necessary clean ups. - * After this method is called, the connector should not work anymore. - */ - void post(); -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/connectors/ConnectorContextHandler.java b/backend/src/main/java/de/learnlib/alex/learning/services/connectors/ConnectorContextHandler.java deleted file mode 100644 index aa4730313..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/connectors/ConnectorContextHandler.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services.connectors; - -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.SymbolParameter; -import de.learnlib.alex.learning.exceptions.LearnerException; -import de.learnlib.mapper.ContextExecutableInputSUL; - -/** - * ContextHandler for the connectors. - */ -public class ConnectorContextHandler implements ContextExecutableInputSUL.ContextHandler { - - /** The pool with the managers for the sul. */ - private final ConnectorManager connectors; - - /** The symbol used to reset the SUL. */ - private final ParameterizedSymbol resetSymbol; - - /** The symbol used after a membership query. */ - private final ParameterizedSymbol postSymbol; - - public ConnectorContextHandler(ConnectorManager connectors, - ParameterizedSymbol resetSymbol, - ParameterizedSymbol postSymbol) { - this.connectors = connectors; - this.resetSymbol = resetSymbol; - this.postSymbol = postSymbol; - } - - @Override - public ConnectorManager createContext() throws LearnerException { - int retries = 0; - Exception exception = null; - while (retries < 2) { - try { - try { - for (Connector connector : connectors) { - connector.reset(); - } - } catch (Exception e) { - throw new LearnerException("An error occurred while resetting a connector.", e); - } - - ExecuteResult resetResult; - try { - // initialize counters defined in the reset symbol as input - final CounterStoreConnector counterStore = connectors.getConnector(CounterStoreConnector.class); - resetSymbol.getSymbol().getInputs().stream() - .filter(in -> in.getParameterType().equals(SymbolParameter.ParameterType.COUNTER)) - .forEach(in -> { - try { - counterStore.get(in.getName()); - } catch (IllegalStateException e) { - counterStore.set(resetSymbol.getSymbol().getProjectId(), in.getName(), 0); - } - }); - resetResult = resetSymbol.execute(connectors); - } catch (Exception e) { - throw new LearnerException("An error occurred while executing the reset symbol.", e); - } - - if (!resetResult.isSuccess()) { - throw new LearnerException("The execution of the reset symbol failed: " - + resetResult.toString() + "."); - } - - return connectors; - } catch (Exception e) { - disposeContext(connectors); - exception = e; - retries++; - } - } - - throw new LearnerException("Failed to create a context. " + exception.getMessage(), exception); - } - - @Override - public void disposeContext(ConnectorManager connectorManager) { - try { - if (this.postSymbol != null) { - this.postSymbol.execute(connectorManager); - } - } catch (Exception ignored) { - } - - try { - connectorManager.dispose(); - } catch (Exception e) { - throw new LearnerException(e.getMessage(), e); - } - } - - /** - * Execute the {@link ConnectorManager#post} method after the learner has finished. - */ - public void post() { - connectors.post(); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/connectors/ConnectorManager.java b/backend/src/main/java/de/learnlib/alex/learning/services/connectors/ConnectorManager.java deleted file mode 100644 index 6a612c48c..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/connectors/ConnectorManager.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services.connectors; - -import de.learnlib.alex.data.entities.ProjectEnvironment; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -/** - * Manager to manage a set of connectors. - */ -public class ConnectorManager implements Iterable { - - /** - * Map of all the connectors by their type. - */ - private final Map, Connector> connectors; - - /** The environment the connectors are used in. */ - private final ProjectEnvironment environment; - - /** - * Default constructor. - */ - public ConnectorManager(ProjectEnvironment environment) { - this.environment = environment; - this.connectors = new HashMap<>(); - } - - /** - * Adds a new connector to the manager. - * - * @param connector - * The instance of the connector to add. - */ - public void addConnector(Connector connector) { - this.connectors.put(connector.getClass(), connector); - } - - /** - * Get the connector specified by a connector class. - * - * @param type - * The class of the connector. - * @param - * The type of the connector. - * @return The connector that matches the specified class. - */ - public T getConnector(Class type) { - return (T) this.connectors.get(type); - } - - @Override - public Iterator iterator() { - return connectors.values().iterator(); - } - - /** Disposes all connectors. */ - public void dispose() { - connectors.values().forEach(Connector::dispose); - } - - /** Clean up all connectors after the learner finished. */ - public void post() { - connectors.values().forEach(Connector::post); - } - - public ProjectEnvironment getEnvironment() { - return environment; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/connectors/CounterStoreConnector.java b/backend/src/main/java/de/learnlib/alex/learning/services/connectors/CounterStoreConnector.java deleted file mode 100644 index 2eddcc777..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/connectors/CounterStoreConnector.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services.connectors; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.dao.CounterDAO; -import de.learnlib.alex.data.entities.Counter; -import de.learnlib.alex.data.entities.Project; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Connector to store and manage counters. - */ -public class CounterStoreConnector implements Connector, Cloneable { - - private static final Logger logger = LoggerFactory.getLogger(CounterStoreConnector.class); - - /** The map that keeps track of all counters used by different urls. url -> (counterName -> counterValue). */ - private final Map countersMap; - - /** An instance of the counterDAO. */ - private final CounterDAO counterDAO; - - /** The current project. */ - private final Project project; - - /** The user that executes the experiment. */ - private final User user; - - /** - * Constructor. - * - * @param counterDAO - * An instance of the counterDAO. - * @param user - * The current user. - * @param project - * The current project. - * @param counterList - * The list of counters in the database to initialize the map with. - */ - public CounterStoreConnector(CounterDAO counterDAO, User user, Project project, List counterList) { - this.counterDAO = counterDAO; - this.project = project; - this.user = user; - this.countersMap = new HashMap<>(); - counterList.forEach(counter -> this.countersMap.put(counter.getName(), counter.getValue())); - } - - @Override - public void reset() { - } - - @Override - public void dispose() { - if (countersMap.isEmpty()) { - return; - } - - // get all counters from the db - final Map counters = new HashMap<>(); - try { - counterDAO.getAll(user, project.getId()).forEach(c -> counters.put(c.getName(), c)); - } catch (NotFoundException ignored) { - } - - // create counters that have not yet been created - // update counters that have been created - for (String name : countersMap.keySet()) { - try { - boolean counterExists = counters.containsKey(name); - if (counterExists) { - counters.get(name).setValue(Math.max(counters.get(name).getValue(), countersMap.get(name))); - counters.put(name, counterDAO.update(user, counters.get(name))); - } else { - Counter counter = createCounter(project.getId(), name, countersMap.get(name)); - counterDAO.create(user, counter); - } - } catch (NotFoundException e) { - e.printStackTrace(); - } - } - } - - @Override - public void post() { - } - - private Counter createCounter(Long projectId, String name, Integer value) { - Counter counter = new Counter(); - counter.setProject(new Project(projectId)); - counter.setName(name); - counter.setValue(value); - return counter; - } - - /** - * Set the value of an existing counter. Creates a new counter implicitly with the specified name and value if it - * does not exist yet. - * - * @param projectId - * The id of the project. - * @param name - * The name of the counter. - * @param value - * The value of the counter. - */ - public void set(Long projectId, String name, Integer value) { - countersMap.put(name, value); - logger.debug("Set the counter '{}' in the project <{}> to '{}'.", name, projectId, value); - } - - /** - * Increment a counter by a positive or negative value. - * - * @param projectId - * The id of the project. - * @param name - * The name of the counter. - * @param incrementBy - * The value to increment or decrement the counter by. - * @throws IllegalStateException - * If the counter 'name' has not been set yet. - */ - public void incrementBy(Long projectId, String name, int incrementBy) { - if (!countersMap.containsKey(name)) { - throw new IllegalStateException("Undefined counter: " + name); - } - - countersMap.put(name, countersMap.get(name) + incrementBy); - - logger.debug("Incremented the counter '{}' in the project <{}> of user <{}>.", name, projectId, - countersMap.get(name)); - } - - /** - * Get the value of an existing counter. - * - * @param name - * The name of the counter. - * @return The positive value of the counter. - * @throws IllegalStateException - * If the counter 'name' has not been set yet. - */ - public Integer get(String name) throws IllegalStateException { - if (!countersMap.containsKey(name)) { - throw new IllegalStateException("Undefined counter: " + name); - } - return countersMap.get(name); - } - - public boolean contains(String name) { - return countersMap.containsKey(name); - } - - /** - * Get the store as read only map. - * - * @return The store. - */ - public Map getStore() { - return Collections.unmodifiableMap(countersMap); - } - - /** - * Copies the connector. - * - * @return A copy of the connector. - */ - @Override - public CounterStoreConnector clone() { - return new CounterStoreConnector(counterDAO, user, project, new ArrayList<>()); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/connectors/FileStoreConnector.java b/backend/src/main/java/de/learnlib/alex/learning/services/connectors/FileStoreConnector.java deleted file mode 100644 index 75febedd2..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/connectors/FileStoreConnector.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services.connectors; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.dao.FileDAO; - -/** - * Connector to store and manage files. - */ -public class FileStoreConnector implements Connector { - - /** The current user. */ - private final User user; - - /** The FileDAO to use. */ - private final FileDAO fileDAO; - - /** - * Constructor. - * - * @param fileDAO - * An instance of the file dao. - * @param user - * The current user. - */ - public FileStoreConnector(FileDAO fileDAO, User user) { - this.user = user; - this.fileDAO = fileDAO; - } - - @Override - public void reset() { - } - - @Override - public void dispose() { - } - - @Override - public void post() { - } - - /** - * Get the absolute path of a file in the uploads directory. - * - * @param projectId - * The id of the project. - * @param fileName - * The name of the file. - * @return The absolute path to the file. - * @throws IllegalStateException - * If no file with 'fileName' has been uploaded. - */ - public String getAbsoluteFileLocation(Long projectId, String fileName) throws IllegalStateException { - try { - return fileDAO.getFileByName(user, projectId, fileName).getAbsolutePath(); - } catch (NotFoundException e) { - throw new IllegalStateException("No file with the name '" + fileName + "' was uploaded into the project " - + projectId + "."); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/connectors/PreparedConnectorContextHandlerFactory.java b/backend/src/main/java/de/learnlib/alex/learning/services/connectors/PreparedConnectorContextHandlerFactory.java deleted file mode 100644 index f9314557d..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/connectors/PreparedConnectorContextHandlerFactory.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services.connectors; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.dao.CounterDAO; -import de.learnlib.alex.data.dao.FileDAO; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.learning.entities.WebDriverConfig; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -/** - * Factor to create a ContextHandler which knows all available connectors. - */ -@Service -public class PreparedConnectorContextHandlerFactory { - - private final CounterDAO counterDAO; - private final FileDAO fileDAO; - - @Autowired - public PreparedConnectorContextHandlerFactory(CounterDAO counterDAO, FileDAO fileDAO) { - this.counterDAO = counterDAO; - this.fileDAO = fileDAO; - } - - /** - * Create a context handler that only requires a URL to create a new context. - * - * @param user - * The user that starts the learning process. - * @param project - * The project. - * @param driverConfig - * The config for the web driver. - * @param resetSymbol - * The symbol to reset the SUL. - * @param postSymbol - * The symbol to execute after each membership query. - * @return The prepared context handler. - */ - public PreparedContextHandler createPreparedContextHandler(User user, - Project project, - WebDriverConfig driverConfig, - ParameterizedSymbol resetSymbol, - ParameterizedSymbol postSymbol) { - return new PreparedContextHandler(counterDAO, fileDAO, user, project, driverConfig, resetSymbol, postSymbol); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/connectors/PreparedContextHandler.java b/backend/src/main/java/de/learnlib/alex/learning/services/connectors/PreparedContextHandler.java deleted file mode 100644 index 2a724cbed..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/connectors/PreparedContextHandler.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services.connectors; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.dao.CounterDAO; -import de.learnlib.alex.data.dao.FileDAO; -import de.learnlib.alex.data.entities.Counter; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.learning.entities.WebDriverConfig; -import java.util.ArrayList; -import java.util.List; - -public class PreparedContextHandler { - private final CounterDAO counterDAO; - private final FileDAO fileDAO; - private final User user; - private final Project project; - private final WebDriverConfig driverConfig; - private final ParameterizedSymbol resetSymbol; - private final ParameterizedSymbol postSymbol; - - public PreparedContextHandler(CounterDAO counterDAO, - FileDAO fileDAO, - User user, - Project project, - WebDriverConfig driverConfig, - ParameterizedSymbol resetSymbol, - ParameterizedSymbol postSymbol) { - this.counterDAO = counterDAO; - this.fileDAO = fileDAO; - this.user = user; - this.project = project; - this.driverConfig = driverConfig; - this.resetSymbol = resetSymbol; - this.postSymbol = postSymbol; - } - - public ConnectorContextHandler create(ProjectEnvironment environment) { - final List counters = new ArrayList<>(); - try { - counters.addAll(counterDAO.getAll(user, project.getId())); - } catch (NotFoundException e) { - e.printStackTrace(); - } - - final ConnectorManager connectors = new ConnectorManager(environment); - connectors.addConnector(new WebSiteConnector(environment, driverConfig)); - connectors.addConnector(new WebServiceConnector(environment)); - connectors.addConnector(new CounterStoreConnector(counterDAO, user, project, counters)); - connectors.addConnector(new VariableStoreConnector()); - connectors.addConnector(new FileStoreConnector(fileDAO, user)); - - return new ConnectorContextHandler(connectors, resetSymbol, postSymbol); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/connectors/VariableStoreConnector.java b/backend/src/main/java/de/learnlib/alex/learning/services/connectors/VariableStoreConnector.java deleted file mode 100644 index c54bbff1b..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/connectors/VariableStoreConnector.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services.connectors; - -import java.util.HashMap; -import java.util.Map; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Connector to hold and manage variables. - */ -public class VariableStoreConnector implements Connector, Cloneable { - - private static final Logger logger = LoggerFactory.getLogger(VariableStoreConnector.class); - - /** The variable store. */ - private final Map store; - - /** - * Default constructor. - */ - public VariableStoreConnector() { - this.store = new HashMap<>(); - } - - @Override - public void reset() { - store.clear(); - } - - @Override - public void dispose() { - } - - @Override - public void post() { - } - - /** - * Set a variable to a certain value. - * - * @param name - * The name of the variable to set. - * @param value - * The value to set. - */ - public void set(String name, String value) { - store.put(name, value); - logger.debug("Set the variable '{}' to the value '{}'.", name, value); - } - - /** - * Get the value of a variable. - * - * @param name - * The variable to get the value from. - * @return The value of the variable. - * @throws IllegalStateException - * If the variable was not set before. - */ - public String get(String name) throws IllegalStateException { - final String variable = store.get(name); - if (variable == null) { - throw new IllegalStateException("Undefined variable: " + name); - } - - logger.debug("Got the variable '{}' with the value '{}'.", name, variable); - return variable; - } - - /** - * Check if the store contains a variable. - * - * @param name - * The name of the variable. - * @return If the variable is present. - */ - public boolean contains(String name) { - return store.containsKey(name); - } - - /** - * Get the store as read only map. - * - * @return The store. - */ - public Map getStore() { - return store; - } - - /** - * Clones the store. - * - * @return The cloned store. - */ - @Override - public VariableStoreConnector clone() { - final VariableStoreConnector clone = new VariableStoreConnector(); - store.forEach(clone::set); - return clone; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/connectors/WebServiceConnector.java b/backend/src/main/java/de/learnlib/alex/learning/services/connectors/WebServiceConnector.java deleted file mode 100644 index 0a4820dae..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/connectors/WebServiceConnector.java +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services.connectors; - -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.learning.services.BaseUrlManager; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Map; -import java.util.Set; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.Invocation; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.Cookie; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.NewCookie; -import javax.ws.rs.core.Response; -import org.glassfish.jersey.client.ClientProperties; - -/** - * A Wrapper around a @{link WebTarget}. - */ -public class WebServiceConnector implements Connector { - - /** Internal field to determine if the target called at least once (-> other fields have a value). */ - private boolean init; - - /** The response HTTP status of the last call done by the connection. */ - private int status; - - /** The response HTTP headers of the last call done by the connection. */ - private MultivaluedMap headers; - - /** The response body of the last call done by the connection. */ - private String body; - - /** The cookies from th last call done by the connection. */ - private Map cookies; - - /** Client for following redirects. */ - private final Client client; - - private final BaseUrlManager baseUrlManager; - - /** - * Constructor which sets the WebTarget to use. - */ - public WebServiceConnector(ProjectEnvironment environment) { - this.client = ClientBuilder.newClient().property(ClientProperties.FOLLOW_REDIRECTS, false); - this.baseUrlManager = new BaseUrlManager(environment); - } - - @Override - public void reset() { - } - - @Override - public void dispose() { - } - - @Override - public void post() { - } - - /** - * Get the response status of the last request. - * - * @return The last status received by the connections. - * @throws java.lang.IllegalStateException - * If no request was done before the method call. - */ - public int getStatus() throws IllegalStateException { - if (!init) { - throw new IllegalStateException(); - } - return status; - } - - /** - * Get the response HTTP header of the last request. - * - * @return The last HTTP header received by the connections. - * @throws java.lang.IllegalStateException - * If no request was done before the method call. - */ - public MultivaluedMap getHeaders() throws IllegalStateException { - if (!init) { - throw new IllegalStateException(); - } - return headers; - } - - /** - * Get the response body of the last request. - * - * @return The last body received by the connections. - * @throws java.lang.IllegalStateException - * If no request was done before the method call. - */ - public String getBody() throws IllegalStateException { - if (!init) { - throw new IllegalStateException(); - } - return body; - } - - /** - * Get the cookies. - * - * @return The cookies. - * @throws IllegalStateException - * If no request was done before the method call. - */ - public Map getCookies() throws IllegalStateException { - if (!init) { - throw new IllegalStateException(); - } - return cookies; - } - - /** - * Do a HTTP GET request. - * - * @param path - * The path to send the request to. - * @param requestHeaders - * The headers to send with the request. - * @param requestCookies - * The cookies to send with the request. - * @param timeout - * The amount of time in ms before the request is canceled. - */ - public void get(String baseUrl, String path, Map requestHeaders, Set requestCookies, int timeout) - throws Exception { - final Response response = getRequestObject(baseUrl, path, requestHeaders, requestCookies, timeout).get(); - rememberResponseComponents(response); - followRedirects(response); - } - - /** - * Do a HTTP POST request. - * - * @param path - * The path to send the request to. - * @param requestHeaders - * The headers to send with the request. - * @param requestCookies - * The cookies to send with the request. - * @param data - * The data to send with the request. - * @param timeout - * The amount of time in ms before the request is canceled. - */ - public void post(String baseUrl, String path, Map requestHeaders, Set requestCookies, String data, int timeout) - throws Exception { - final Entity body = getBody(requestHeaders, data); - final Response response = getRequestObject(baseUrl, path, requestHeaders, requestCookies, timeout).post(body); - rememberResponseComponents(response); - followRedirects(response); - } - - /** - * Do a HTTP PUT request. - * - * @param path - * The path to send the request to. - * @param requestHeaders - * The headers to send with the request. - * @param requestCookies - * The cookies to send with the request. - * @param data - * The data to send with the request. - * @param timeout - * The amount of time in ms before the request is canceled. - */ - public void put(String baseUrl, String path, Map requestHeaders, Set requestCookies, - String data, int timeout) throws Exception { - final Entity body = getBody(requestHeaders, data); - final Response response = getRequestObject(baseUrl, path, requestHeaders, requestCookies, timeout).put(body); - rememberResponseComponents(response); - followRedirects(response); - } - - /** - * Perform an HTTP PATCH request. - * - * @param path - * The path to send the request to. - * @param requestHeaders - * The headers to send with the request. - * @param requestCookies - * The cookies to send with the request. - * @param data - * The data to send with the request. - * @param timeout - * The amount of time in ms before the request is canceled. - */ - public void patch(String baseUrl, String path, Map requestHeaders, Set requestCookies, - String data, int timeout) throws Exception { - final Entity body = getBody(requestHeaders, data); - final Response response = getRequestObject(baseUrl, path, requestHeaders, requestCookies, timeout).method("PATCH", body); - rememberResponseComponents(response); - followRedirects(response); - } - - /** - * Do a HTTP DELETE request. - * - * @param path - * The path to send the request to. - * @param requestHeaders - * The headers to send with the request. - * @param requestCookies - * The cookies to send with the request. - * @param timeout - * The amount of time in ms before the request is canceled. - */ - public void delete(String baseUrl, String path, Map requestHeaders, Set requestCookies, int timeout) throws Exception { - final Response response = getRequestObject(baseUrl, path, requestHeaders, requestCookies, timeout).delete(); - rememberResponseComponents(response); - followRedirects(response); - } - - /** - * Reset the connector and the SUL. - * - * @param resetUrl - * The url (based on the base url) to reset the SUL. - */ - public void reset(String resetUrl) { - client.target("").path(resetUrl).request().get(); - this.init = false; - } - - /** - * Multi setter for all the fields based on the response. - * - * @param response - * The response all other fields will be based on. - */ - private void rememberResponseComponents(Response response) { - status = response.getStatus(); - headers = response.getHeaders(); - body = response.readEntity(String.class); - cookies = response.getCookies(); - init = true; - } - - private void followRedirects(Response response) { - while (response.getStatus() == Response.Status.FOUND.getStatusCode()) { // 302 - final String location = response.getHeaderString("Location"); - response = client.target(location).request().get(); - - status = response.getStatus(); - headers = response.getHeaders(); - body = response.readEntity(String.class); - - // Overwrite cookies from previous requests if there are new cookies, otherwise keep the old ones. - // This way, cookies that may be required don't get lost in redirects. - if (!response.getCookies().isEmpty()) { - cookies = response.getCookies(); - } - } - } - - /** - * Creates a request object that is passed to further REST actions. - * - * @param path - * The URI that is called. - * @param requestHeaders - * The HTTP headers of the request. - * @param requestCookies - * The cookies of the request. - * @param timeout - * The amount of time in ms before the request is canceled. - * @return The request object. - */ - private Invocation.Builder getRequestObject(String baseUrl, String path, Map requestHeaders, - Set requestCookies, int timeout) throws Exception { - final String[] splitPath = path.split("\\?"); - - final String url = baseUrlManager.getAbsoluteUrl(baseUrl, splitPath[0]); - try { - new URL(url); - } catch (MalformedURLException e) { - throw new Exception("The URL is malformed."); - } - - WebTarget tmpTarget = client.target(url); - - if (splitPath.length > 1) { - for (final String queryParam : splitPath[1].split("&")) { - final String[] queryParamPair = queryParam.split("\\="); - - if (queryParamPair.length == 2) { - tmpTarget = tmpTarget.queryParam(queryParamPair[0], queryParamPair[1]); - } - } - } - final Invocation.Builder builder = tmpTarget.request(); - requestHeaders.forEach(builder::header); - requestCookies.forEach(builder::cookie); - - builder.property(ClientProperties.CONNECT_TIMEOUT, timeout); - builder.property(ClientProperties.READ_TIMEOUT, timeout); - - return builder; - } - - private Entity getBody(Map requestHeaders, String data) { - if (requestHeaders.containsKey("Content-Type")) { - return Entity.entity(data, requestHeaders.get("Content-Type")); - } else { - return Entity.json(data); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/connectors/WebSiteConnector.java b/backend/src/main/java/de/learnlib/alex/learning/services/connectors/WebSiteConnector.java deleted file mode 100644 index 5cb9c19ab..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/connectors/WebSiteConnector.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services.connectors; - -import de.learnlib.alex.common.utils.CSSUtils; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.data.entities.actions.Credentials; -import de.learnlib.alex.learning.entities.WebDriverConfig; -import de.learnlib.alex.learning.services.BaseUrlManager; -import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.List; -import java.util.concurrent.TimeUnit; -import org.openqa.selenium.By; -import org.openqa.selenium.JavascriptExecutor; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.OutputType; -import org.openqa.selenium.TakesScreenshot; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Connector to communicate with a WebSite. This is a facade around Seleniums {@link WebDriver}. - */ -public class WebSiteConnector implements Connector { - - private static final Logger logger = LoggerFactory.getLogger(WebSiteConnector.class); - - /** How often it should be tried to navigate to a given URL. */ - private static final int MAX_RETRIES = 10; - - /** The browser to use. */ - private final WebDriverConfig driverConfig; - - /** A managed base url to use. */ - private final BaseUrlManager baseUrlManager; - - /** The driver used to send and receive data to a WebSite. */ - private WebDriver driver; - - /** The last visited frame. */ - private WebElement lastFrame = null; - - /** - * Constructor. - */ - public WebSiteConnector(ProjectEnvironment environment, WebDriverConfig driverConfig) { - this.baseUrlManager = new BaseUrlManager(environment); - this.driverConfig = driverConfig; - } - - @Override - public void reset() { - } - - @Override - public void dispose() { - if (driver != null) { - driver.manage().deleteAllCookies(); - if (driver instanceof JavascriptExecutor) { - final JavascriptExecutor js = (JavascriptExecutor) driver; - js.executeScript("window.localStorage.clear();"); - js.executeScript("window.sessionStorage.clear();"); - } - } - } - - @Override - public void post() { - if (driver != null) { - driver.quit(); - } - } - - /** Refreshes the browser window. */ - public void refresh() { - if (this.driver != null) { - this.driver.navigate().refresh(); - } - } - - /** - * Restarts the browser. - * - * @throws Exception - * In case something during the instantiation of the browser goes wrong. - */ - public void restart() throws Exception { - if (this.driver != null) { - this.driver.quit(); - this.driver = driverConfig.createWebDriver(); - } - } - - /** - * Do a HTTP GET request within the browser. Optionally credentials for HTTP Basic Auth can be provided. - * - * @param path - * The path to send the request to. - * @param credentials - * The credential to use. Can be null. - * @throws Exception - * If the application could not connect to the web driver. - */ - public void get(String baseUrl, String path, Credentials credentials) throws Exception { - if (this.driver == null) { - this.driver = driverConfig.createWebDriver(); - } - - final String url = baseUrlManager.getAbsoluteUrl(baseUrl, path, credentials); - try { - new URL(url); - } catch (MalformedURLException e) { - throw new Exception("The URL is malformed."); - } - - int numRetries = 0; - while (numRetries < MAX_RETRIES) { - try { - driver.navigate().to(url); - break; - } catch (Exception e1) { - logger.warn(LoggerMarkers.LEARNER, "Failed to get URL", e1); - - numRetries++; - try { - restart(); - TimeUnit.SECONDS.sleep(1); - } catch (Exception e2) { - logger.warn(LoggerMarkers.LEARNER, "Failed to dispose", e2); - } - } - } - - if (numRetries == MAX_RETRIES) { - throw new Exception("Error connecting with the web driver."); - } - } - - /** - * Get a {@link WebElement} from the site using a valid css query. - * - * @param locator - * The query to search for the element. - * @return A WebElement. - * @throws NoSuchElementException - * If no element was found. - */ - public WebElement getElement(WebElementLocator locator) throws NoSuchElementException { - switch (locator.getType()) { - case XPATH: - return driver.findElement(By.xpath(locator.getSelector())); - case CSS: - return driver.findElement(By.cssSelector(CSSUtils.escapeSelector(locator.getSelector()))); - case JS: - if (driver instanceof JavascriptExecutor) { - try { - return (WebElement) ((JavascriptExecutor) driver).executeScript(locator.getSelector()); - } catch (ClassCastException e) { - throw new NoSuchElementException("Return result is not a WebElement"); - } - } - default: - throw new NoSuchElementException("Invalid selector type"); - } - } - - /** - * Same as {@link #getElement(WebElementLocator)} but returns a list of web elements. - * - * @param locator - * The query to search for the element. - * @return A list of elements. - * @throws NoSuchElementException - * If no element was found. - */ - public List getElements(WebElementLocator locator) throws NoSuchElementException { - switch (locator.getType()) { - case XPATH: - return driver.findElements(By.xpath(locator.getSelector())); - case CSS: - return driver.findElements(By.cssSelector(CSSUtils.escapeSelector(locator.getSelector()))); - case JS: - if (driver instanceof JavascriptExecutor) { - try { - return (List) ((JavascriptExecutor) driver).executeScript(locator.getSelector()); - } catch (ClassCastException e) { - throw new NoSuchElementException("Return result is not a WebElement"); - } - } - default: - throw new NoSuchElementException("Invalid selector type"); - } - } - - /** - * Get the currently used web driver. - * - * @return the current web driver - */ - public WebDriver getDriver() { - return driver; - } - - public WebElement getLastFrame() { - return lastFrame; - } - - public void setLastFrame(WebElement lastFrame) { - this.lastFrame = lastFrame; - } - - public File takeScreenshot() { - if (driver != null) { - return ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE); - } - return null; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/export/LearnerSetupsExporter.java b/backend/src/main/java/de/learnlib/alex/learning/services/export/LearnerSetupsExporter.java deleted file mode 100644 index 5b39efef6..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/export/LearnerSetupsExporter.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services.export; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.databind.module.SimpleModule; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.data.entities.ProjectEnvironmentVariable; -import de.learnlib.alex.data.entities.ProjectUrl; -import de.learnlib.alex.data.entities.SymbolParameter; -import de.learnlib.alex.data.entities.SymbolParameterValue; -import de.learnlib.alex.data.entities.export.ExportableEntity; -import de.learnlib.alex.data.services.export.EntityExporter; -import de.learnlib.alex.data.services.export.SymbolsExporter; -import de.learnlib.alex.learning.dao.LearnerSetupDAO; -import de.learnlib.alex.learning.entities.LearnerSetup; -import de.learnlib.alex.learning.entities.export.LearnerSetupExportableEntity; -import de.learnlib.alex.modelchecking.entities.LtsFormula; -import de.learnlib.alex.modelchecking.entities.LtsFormulaSuite; -import de.learnlib.alex.modelchecking.entities.ModelCheckingConfig; -import de.learnlib.alex.modelchecking.services.export.LtsFormulaSuitesExporter; -import java.util.List; -import java.util.stream.Collectors; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(rollbackFor = Exception.class, readOnly = true) -public class LearnerSetupsExporter extends EntityExporter { - - private final LearnerSetupDAO learnerSetupDAO; - - @Autowired - public LearnerSetupsExporter(LearnerSetupDAO learnerSetupDAO) { - super(); - - this.learnerSetupDAO = learnerSetupDAO; - - om.addMixIn(Project.class, IgnoreFieldsForProjectMixin.class); - om.addMixIn(ParameterizedSymbol.class, IgnoreIdFieldMixin.class); - om.addMixIn(SymbolParameter.class, IgnoreIdFieldMixin.class); - om.addMixIn(SymbolParameterValue.class, IgnoreIdFieldMixin.class); - om.addMixIn(LearnerSetup.class, IgnoreFieldsForLearnerSetupMixin.class); - om.addMixIn(ProjectEnvironment.class, IgnoreFieldsForProjectEnvironmentMixin.class); - om.addMixIn(ProjectUrl.class, IgnoreFieldsForProjectEnvironmentUrlMixin.class); - om.addMixIn(ProjectEnvironmentVariable.class, IgnoreFieldsForProjectEnvironmentVariableMixin.class); - om.addMixIn(ModelCheckingConfig.class, IgnoreIdFieldMixin.class); - om.addMixIn(LtsFormulaSuite.class, LtsFormulaSuitesExporter.IgnoreFieldsForLtsFormulaSuiteMixin.class); - om.addMixIn(LtsFormula.class, LtsFormulaSuitesExporter.IgnoreFieldsForLtsFormulaMixin.class); - - final var module = new SimpleModule(); - module.addSerializer(new SymbolsExporter.ParameterizedSymbolSerializer(om, ParameterizedSymbol.class)); - om.registerModule(module); - } - - public ExportableEntity export(User user, Long projectId) throws Exception { - final var setups = learnerSetupDAO.getAll(user, projectId).stream() - .filter(LearnerSetup::isSaved) - .collect(Collectors.toList()); - - return new LearnerSetupExportableEntity(version, om.readTree(om.writeValueAsString(setups))); - } - - private abstract static class IgnoreFieldsForProjectMixin extends IgnoreIdFieldMixin { - @JsonIgnore - abstract Long getProjectId(); - - @JsonIgnore - abstract List getOwnerIds(); - - @JsonIgnore - abstract List getMemberIds(); - } - - private abstract static class IgnoreFieldsForLearnerSetupMixin extends IgnoreIdFieldMixin { - @JsonIgnore - abstract Long getProjectId(); - - @JsonIgnore - abstract Project getProject(); - } - - private abstract static class IgnoreFieldsForProjectEnvironmentMixin extends IgnoreIdFieldMixin { - @JsonIgnore - abstract Long getProjectId(); - } - - private abstract static class IgnoreFieldsForProjectEnvironmentUrlMixin extends IgnoreIdFieldMixin { - @JsonIgnore - abstract Long getEnvironmentId(); - } - - private abstract static class IgnoreFieldsForProjectEnvironmentVariableMixin extends IgnoreIdFieldMixin { - @JsonIgnore - abstract Long getEnvironmentId(); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/export/TestExecutionConfigsExporter.java b/backend/src/main/java/de/learnlib/alex/learning/services/export/TestExecutionConfigsExporter.java deleted file mode 100644 index 04918e2c1..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/export/TestExecutionConfigsExporter.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services.export; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.data.entities.ProjectEnvironmentVariable; -import de.learnlib.alex.data.entities.ProjectUrl; -import de.learnlib.alex.data.entities.export.ExportableEntity; -import de.learnlib.alex.data.services.export.EntityExporter; -import de.learnlib.alex.testing.dao.TestExecutionConfigDAO; -import de.learnlib.alex.testing.entities.Test; -import de.learnlib.alex.testing.entities.TestExecutionConfig; -import de.learnlib.alex.testing.entities.export.TestExecutionConfigExportableEntity; -import java.util.List; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(rollbackFor = Exception.class, readOnly = true) -public class TestExecutionConfigsExporter extends EntityExporter { - - private final TestExecutionConfigDAO testExecutionConfigDAO; - - @Autowired - public TestExecutionConfigsExporter(TestExecutionConfigDAO testExecutionConfigDAO) { - super(); - - this.testExecutionConfigDAO = testExecutionConfigDAO; - - om.addMixIn(TestExecutionConfig.class, IgnoreFieldsForTestExecutionConfigMixin.class); - om.addMixIn(ProjectEnvironment.class, IgnoreFieldsForProjectEnvironmentMixin.class); - } - - public ExportableEntity export(User user, Long projectId) throws Exception { - final var configs = testExecutionConfigDAO.getAll(user, projectId); - - return new TestExecutionConfigExportableEntity(version, om.readTree(om.writeValueAsString(configs))); - } - - private abstract static class IgnoreFieldsForTestExecutionConfigMixin extends IgnoreIdFieldMixin { - @JsonIgnore - abstract Project getProject(); - - @JsonIgnore - abstract Long getProjectId(); - - @JsonIgnore - abstract List getTests(); - - @JsonIgnore - abstract Long getEnvironmentId(); - } - - private abstract static class IgnoreFieldsForProjectEnvironmentMixin extends IgnoreIdFieldMixin { - @JsonIgnore - abstract Long getProjectId(); - - @JsonIgnore - abstract List getUrls(); - - @JsonIgnore - abstract boolean isDefault(); - - @JsonIgnore - abstract List getVariables(); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/oracles/ContextAwareSulOracle.java b/backend/src/main/java/de/learnlib/alex/learning/services/oracles/ContextAwareSulOracle.java deleted file mode 100644 index e35124d51..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/oracles/ContextAwareSulOracle.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services.oracles; - -import de.learnlib.alex.common.exceptions.LearnerInterruptedException; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.learning.services.SymbolMapper; -import de.learnlib.alex.learning.services.connectors.ConnectorContextHandler; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.api.SUL; -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.api.query.Query; -import de.learnlib.mapper.ContextExecutableInputSUL; -import de.learnlib.mapper.SULMappers; -import de.learnlib.mapper.api.ContextExecutableInput; -import de.learnlib.oracle.membership.SULOracle; -import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.subjects.Subject; -import java.util.Collection; -import java.util.concurrent.atomic.AtomicBoolean; -import net.automatalib.words.Word; - -/** - * Wrapper for a {@link SULOracle} that knows its context. - */ -public class ContextAwareSulOracle implements MembershipOracle> { - - /** The oracle to pose queries to. */ - private final SULOracle sulOracle; - - /** The context handler for the learning process. */ - private final ConnectorContextHandler contextHandler; - - private final AtomicBoolean aborted = new AtomicBoolean(false); - - private final Disposable abortSubscription; - - /** - * Constructor. - * - * @param symbolMapper - * The shared instance of the symbol mapper. - * @param contextHandler - * {@link #contextHandler}. - */ - public ContextAwareSulOracle(SymbolMapper symbolMapper, ConnectorContextHandler contextHandler, Subject abortSubject) { - this.contextHandler = contextHandler; - - final ContextExecutableInputSUL, ExecuteResult, ConnectorManager> ceiSUL - = new ContextExecutableInputSUL<>(contextHandler); - final SUL sul = SULMappers.apply(symbolMapper, ceiSUL); - this.sulOracle = new SULOracle<>(sul); - - this.abortSubscription = abortSubject.subscribe(aborted::set); - } - - @Override - public void processQueries(Collection>> queries) { - for (var query: queries) { - if (aborted.get()) { - throw new LearnerInterruptedException("The learning process has been aborted by the user"); - } else { - sulOracle.processQuery(query); - } - } - } - - /** Clears the context. */ - public void shutdown() { - abortSubscription.dispose(); - contextHandler.post(); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/oracles/DelegationOracle.java b/backend/src/main/java/de/learnlib/alex/learning/services/oracles/DelegationOracle.java deleted file mode 100644 index 141c86277..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/oracles/DelegationOracle.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services.oracles; - -import de.learnlib.alex.common.exceptions.LearnerInterruptedException; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.learning.exceptions.LearnerException; -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.api.query.Query; -import java.util.Collection; -import javax.annotation.ParametersAreNonnullByDefault; -import net.automatalib.words.Word; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Oracle that delegates queries to another oracle that can be exchanged. - * - * @param - * Input symbol type. - * @param - * Output symbol type. - */ -@ParametersAreNonnullByDefault -public class DelegationOracle implements MembershipOracle> { - - private static final Logger logger = LoggerFactory.getLogger(DelegationOracle.class); - - /** How often the queries should be posed in case an exception is thrown. */ - private static final int MAX_RETRIES = 5; - - /** How long to wait before retrying. */ - private static final int SLEEP_TIME = 2000; - - /** The sul the membership queries should be posed to. */ - private MembershipOracle> delegate; - - @Override - public void processQueries(Collection>> queries) { - int i = 0; - Exception lastException; - while (i < MAX_RETRIES) { - try { - delegate.processQueries(queries); - break; - } catch (LearnerInterruptedException e) { - throw new LearnerException(e.getMessage()); - } catch (Exception e) { - e.printStackTrace(); - lastException = e; - logger.warn(LoggerMarkers.LEARNER, "Failed to execute query on {}. try. Retry in {}ms", i + 1, SLEEP_TIME); - i++; - - if (i == MAX_RETRIES) { - logger.error(LoggerMarkers.LEARNER, "Failed to execute query for " + MAX_RETRIES + " times\"", lastException); - throw new LearnerException(lastException.getMessage()); - } else { - try { - Thread.sleep(SLEEP_TIME); - } catch (InterruptedException e2) { - } - } - } - } - } - - public void setDelegate(MembershipOracle> delegate) { - this.delegate = delegate; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/oracles/FuzzyStateCoverEQOracle.java b/backend/src/main/java/de/learnlib/alex/learning/services/oracles/FuzzyStateCoverEQOracle.java deleted file mode 100644 index 27dbf98c9..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/oracles/FuzzyStateCoverEQOracle.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services.oracles; - -import com.google.common.collect.Iterators; -import com.google.common.collect.Streams; -import de.learnlib.api.oracle.EquivalenceOracle; -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.api.query.DefaultQuery; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.Random; -import java.util.stream.Collectors; -import net.automatalib.automata.transducers.MealyMachine; -import net.automatalib.util.automata.Automata; -import net.automatalib.words.Word; -import org.checkerframework.checker.nullness.qual.Nullable; - -public class FuzzyStateCoverEQOracle implements EquivalenceOracle.MealyEquivalenceOracle { - - private final MembershipOracle> mqOracle; - private final int minLength; - private final int maxLength; - private final int maxNoOfTests; - private final Random random; - private final int batchSize; - - public FuzzyStateCoverEQOracle( - MembershipOracle> mqOracle, - int minLength, - int maxLength, - int maxNoOfTests, - Random random, - int batchSize - ) { - this.minLength = minLength; - this.maxLength = maxLength; - this.maxNoOfTests = maxNoOfTests; - this.random = random; - this.mqOracle = mqOracle; - this.batchSize = batchSize; - } - - @Override - public @Nullable DefaultQuery> findCounterExample(MealyMachine hypothesis, - Collection inputs) { - final List> accessSequences = Automata.stateCover(hypothesis, inputs); - final List symbolList = new ArrayList<>(inputs); - - try { - for (int i = 0; i < maxNoOfTests; i++) { - final var batch = new ArrayList>>(); - - for (Word accessSequence : accessSequences) { - var query = accessSequence.concat(Word.epsilon()); - - final int length = minLength + random.nextInt((maxLength - minLength) + 1); - - for (int j = 0; j < length; j++) { - int symbolIndex = random.nextInt(symbolList.size()); - I sym = symbolList.get(symbolIndex); - query = query.append(sym); - } - - batch.add(new DefaultQuery<>(query)); - } - - var batches = Streams - .stream(Iterators.partition(batch.iterator(), this.batchSize)) - .collect(Collectors.toList()); - - for (var b : batches) { - mqOracle.processQueries(b); - for (var query : b) { - if (!Objects.equals(hypothesis.computeOutput(query.getInput()), query.getOutput())) { - return query; - } - } - } - } - } catch (Exception e) { - e.printStackTrace(); - return null; - } - - return null; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/oracles/QueryMonitorOracle.java b/backend/src/main/java/de/learnlib/alex/learning/services/oracles/QueryMonitorOracle.java deleted file mode 100644 index 3cc465fb2..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/oracles/QueryMonitorOracle.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services.oracles; - -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.api.query.Query; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import javax.annotation.ParametersAreNonnullByDefault; -import net.automatalib.words.Word; - -/** - * Oracle that allows query pre and post processing. - * - * @param - * Input symbol type. - * @param - * Output symbol type. - */ -@ParametersAreNonnullByDefault -public class QueryMonitorOracle implements MembershipOracle> { - - /** - * The query listener interface. - * - * @param - * Input symbol type. - * @param - * Output symbol type. - */ - public interface QueryProcessingListener { - - /** - * Process incoming queries. - * - * @param queries - * The queries that are or have been processed. - */ - void process(Collection>> queries); - } - - /** The sul the membership queries should be posed to. */ - private final MembershipOracle> delegate; - - /** The pre process listeners. */ - private final List> preProcessListeners; - - /** The pre process listeners. */ - private final List> postProcessListeners; - - /** - * Constructor. - * - * @param delegate - * The membership oracle the queries are delegated to. - */ - public QueryMonitorOracle(MembershipOracle> delegate) { - this.delegate = delegate; - this.preProcessListeners = new ArrayList<>(); - this.postProcessListeners = new ArrayList<>(); - } - - /** - * Adds a pre process listener to the list. - * - * @param listener - * The listener. - */ - public void addPreProcessingListener(QueryProcessingListener listener) { - this.preProcessListeners.add(listener); - } - - /** - * Adds a post process listener to the list. - * - * @param listener - * The listener. - */ - public void addPostProcessingListener(QueryProcessingListener listener) { - this.preProcessListeners.add(listener); - } - - @Override - public void processQueries(Collection>> queries) { - if (queries.size() > 0) { - preProcessListeners.forEach(listener -> listener.process(queries)); - delegate.processQueries(queries); - postProcessListeners.forEach(listener -> listener.process(queries)); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/learning/services/oracles/StatisticsOracle.java b/backend/src/main/java/de/learnlib/alex/learning/services/oracles/StatisticsOracle.java deleted file mode 100644 index e8d6f4654..000000000 --- a/backend/src/main/java/de/learnlib/alex/learning/services/oracles/StatisticsOracle.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services.oracles; - -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.api.query.Query; -import java.util.Collection; - -public class StatisticsOracle implements MembershipOracle { - - private final MembershipOracle delegate; - - private long queryCount = 0; - - private long symbolCount = 0; - - public StatisticsOracle(MembershipOracle delegate) { - this.delegate = delegate; - } - - @Override - public void processQueries(Collection> queries) { - queryCount += queries.size(); - for (Query qry : queries) { - symbolCount += qry.getInput().length(); - } - delegate.processQueries(queries); - } - - public void reset() { - queryCount = 0; - symbolCount = 0; - } - - public long getQueryCount() { - return queryCount; - } - - public long getSymbolCount() { - return symbolCount; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/dao/LtsFormulaDAO.java b/backend/src/main/java/de/learnlib/alex/modelchecking/dao/LtsFormulaDAO.java deleted file mode 100644 index 3f97ceab3..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/dao/LtsFormulaDAO.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.dao; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.learning.repositories.LearnerResultStepRepository; -import de.learnlib.alex.modelchecking.entities.LtsFormula; -import de.learnlib.alex.modelchecking.entities.LtsFormulaSuite; -import de.learnlib.alex.modelchecking.repositories.LtsFormulaRepository; -import de.learnlib.alex.modelchecking.repositories.ModelCheckingResultRepository; -import java.util.List; -import java.util.stream.Collectors; -import net.automatalib.modelcheckers.ltsmin.LTSminLTLParser; -import org.apache.shiro.authz.UnauthorizedException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(rollbackFor = Exception.class) -public class LtsFormulaDAO { - - private final LtsFormulaRepository ltsFormulaRepository; - private final LtsFormulaSuiteDAO ltsFormulaSuiteDAO; - private final ProjectRepository projectRepository; - private final LearnerResultStepRepository learnerResultStepRepository; - private final ModelCheckingResultRepository modelCheckingResultRepository; - - @Autowired - public LtsFormulaDAO( - LtsFormulaRepository ltsFormulaRepository, - @Lazy LtsFormulaSuiteDAO ltsFormulaSuiteDAO, - ProjectRepository projectRepository, - LearnerResultStepRepository learnerResultStepRepository, - ModelCheckingResultRepository modelCheckingResultRepository - ) { - this.ltsFormulaRepository = ltsFormulaRepository; - this.ltsFormulaSuiteDAO = ltsFormulaSuiteDAO; - this.projectRepository = projectRepository; - this.learnerResultStepRepository = learnerResultStepRepository; - this.modelCheckingResultRepository = modelCheckingResultRepository; - } - - public LtsFormula create(User user, Long projectId, Long suiteId, LtsFormula formula) { - LTSminLTLParser.requireValidIOFormula(formula.getFormula()); - - final LtsFormulaSuite suite = ltsFormulaSuiteDAO.get(user, projectId, suiteId); - - final LtsFormula f = new LtsFormula(); - f.setFormula(formula.getFormula()); - f.setName(formula.getName()); - f.setSuite(suite); - - return ltsFormulaRepository.save(f); - } - - public List getByIds(User user, Long projectId, List formulaIds) { - final Project project = projectRepository.findById(projectId) - .orElseThrow(() -> new NotFoundException("Project could not be found")); - - final List formulas = ltsFormulaRepository.findAllByIdIn(formulaIds); - for (LtsFormula formula : formulas) { - checkAccess(user, project, formula.getSuite(), formula); - } - - return formulas; - } - - public LtsFormula update(User user, Long projectId, Long suiteId, LtsFormula formula) { - LTSminLTLParser.requireValidIOFormula(formula.getFormula()); - - final LtsFormulaSuite suite = ltsFormulaSuiteDAO.get(user, projectId, suiteId); - final LtsFormula formulaInDb = ltsFormulaRepository.findById(formula.getId()).orElse(null); - checkAccess(user, suite.getProject(), suite, formulaInDb); - - formulaInDb.setName(formula.getName()); - formulaInDb.setFormula(formula.getFormula()); - - return ltsFormulaRepository.save(formulaInDb); - } - - public List updateParent(User user, Long projectId, Long suiteId, List formulaIds, LtsFormulaSuite targetSuite) { - final LtsFormulaSuite oldSuite = ltsFormulaSuiteDAO.get(user, projectId, suiteId); - final LtsFormulaSuite newSuite = ltsFormulaSuiteDAO.get(user, projectId, targetSuite.getId()); - - final List formulas = ltsFormulaRepository.findAllBySuite_IdAndIdIn(suiteId, formulaIds); - for (LtsFormula f : formulas) { - checkAccess(user, oldSuite.getProject(), oldSuite, f); - f.setSuite(newSuite); - } - - return ltsFormulaRepository.saveAll(formulas); - } - - public void delete(User user, Long projectId, Long suiteId, Long formulaId) { - final var suite = ltsFormulaSuiteDAO.get(user, projectId, suiteId); - final var formula = ltsFormulaRepository.findById(formulaId).orElse(null); - checkAccess(user, suite.getProject(), suite, formula); - delete(projectId, formula); - } - - public void delete(User user, Long projectId, Long suiteId, List formulaIds) { - for (final Long id : formulaIds) { - delete(user, projectId, suiteId, id); - } - } - - public void delete(Long projectId, LtsFormula formula) { - // remove model checking results that reference the formula - final var learnerResultSteps = learnerResultStepRepository.findAllByResult_Project_Id(projectId).stream() - .filter(s -> !s.getModelCheckingResults().isEmpty()) - .collect(Collectors.toList()); - - learnerResultSteps.forEach(s -> - s.getModelCheckingResults().removeIf(r -> r.getFormula().getId().equals(formula.getId())) - ); - - learnerResultStepRepository.saveAll(learnerResultSteps); - modelCheckingResultRepository.deleteAllByFormula_Id(formula.getId()); - ltsFormulaRepository.delete(formula); - } - - public void checkAccess(User user, Project project, LtsFormulaSuite suite, LtsFormula formula) { - ltsFormulaSuiteDAO.checkAccess(user, project, suite); - - if (formula == null) { - throw new NotFoundException("The formula could not be found."); - } - - if (!suite.getId().equals(formula.getSuite().getId())) { - throw new UnauthorizedException("You are not allowed to access the resource."); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/dao/LtsFormulaSuiteDAO.java b/backend/src/main/java/de/learnlib/alex/modelchecking/dao/LtsFormulaSuiteDAO.java deleted file mode 100644 index f98e3b615..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/dao/LtsFormulaSuiteDAO.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.dao; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.learning.repositories.LearnerSetupRepository; -import de.learnlib.alex.modelchecking.entities.LtsFormulaSuite; -import de.learnlib.alex.modelchecking.repositories.LtsFormulaSuiteRepository; -import java.util.List; -import org.apache.shiro.authz.UnauthorizedException; -import org.hibernate.Hibernate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(rollbackFor = Exception.class) -public class LtsFormulaSuiteDAO { - - private final ProjectDAO projectDAO; - private final LtsFormulaSuiteRepository formulaSuiteRepository; - private final LearnerSetupRepository learnerSetupRepository; - private final LtsFormulaDAO ltsFormulaDAO; - - @Autowired - public LtsFormulaSuiteDAO( - ProjectDAO projectDAO, - LtsFormulaSuiteRepository formulaSuiteRepository, - LearnerSetupRepository learnerSetupRepository, - LtsFormulaDAO ltsFormulaDAO - ) { - this.projectDAO = projectDAO; - this.formulaSuiteRepository = formulaSuiteRepository; - this.learnerSetupRepository = learnerSetupRepository; - this.ltsFormulaDAO = ltsFormulaDAO; - } - - public List getAll(User user, Long projectId) { - final Project project = projectDAO.getByID(user, projectId); - final List suites = formulaSuiteRepository.findAllByProject_Id(project.getId()); - suites.forEach(this::loadLazyRelations); - return suites; - } - - public LtsFormulaSuite get(User user, Long projectId, Long suiteId) { - final Project project = projectDAO.getByID(user, projectId); - final LtsFormulaSuite suiteInDb = formulaSuiteRepository.findById(suiteId).orElse(null); - checkAccess(user, project, suiteInDb); - return loadLazyRelations(suiteInDb); - } - - public LtsFormulaSuite create(User user, Long projectId, LtsFormulaSuite suite) { - final Project project = projectDAO.getByID(user, projectId); - checkSuiteNameIsUnique(projectId, suite.getName()); - - final LtsFormulaSuite s = new LtsFormulaSuite(); - s.setName(suite.getName()); - s.setProject(project); - - final LtsFormulaSuite createdSuite = formulaSuiteRepository.save(s); - return loadLazyRelations(createdSuite); - } - - public LtsFormulaSuite update(User user, Long projectId, Long suiteId, LtsFormulaSuite suite) { - final LtsFormulaSuite suiteInDb = get(user, projectId, suiteId); - checkSuiteNameIsUnique(projectId, suiteId, suite.getName()); - - suiteInDb.setName(suite.getName()); - - final LtsFormulaSuite updatedSuite = formulaSuiteRepository.save(suiteInDb); - return loadLazyRelations(updatedSuite); - } - - public void delete(User user, Long projectId, Long suiteId) { - final LtsFormulaSuite suiteInDb = get(user, projectId, suiteId); - - // delete references in model checking configs of learner setups - final var setups = learnerSetupRepository.findAllByProject_Id(projectId); - for (var setup : setups) { - var config = setup.getModelCheckingConfig(); - if (config.getFormulaSuites().contains(suiteInDb)) { - config.getFormulaSuites().remove(suiteInDb); - learnerSetupRepository.save(setup); - } - } - - for (var formula : suiteInDb.getFormulas()) { - ltsFormulaDAO.delete(projectId, formula); - } - suiteInDb.getFormulas().clear(); - - formulaSuiteRepository.delete(suiteInDb); - } - - public void delete(User user, Long projectId, List suiteIds) { - for (Long id : suiteIds) { - delete(user, projectId, id); - } - } - - public void checkSuiteNameIsUnique(Long projectId, String name) { - if (formulaSuiteRepository.findByProject_IdAndName(projectId, name) != null) { - throw new IllegalArgumentException("The name of the formula suite is not unique."); - } - } - - public void checkSuiteNameIsUnique(Long projectId, Long suiteId, String name) { - final LtsFormulaSuite suite = formulaSuiteRepository.findByProject_IdAndName(projectId, name); - if (suite != null && !suite.getId().equals(suiteId)) { - throw new IllegalArgumentException("The name of the formula suite is not unique."); - } - } - - public void checkAccess(User user, Project project, LtsFormulaSuite suite) { - projectDAO.checkAccess(user, project); - - if (suite == null) { - throw new NotFoundException("The formula suite could not be found."); - } - - if (!suite.getProject().getId().equals(project.getId())) { - throw new UnauthorizedException("You are not allowed to access the resource."); - } - } - - public LtsFormulaSuite loadLazyRelations(LtsFormulaSuite suite) { - Hibernate.initialize(suite.getFormulas()); - return suite; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/dao/ModelCheckingConfigDAO.java b/backend/src/main/java/de/learnlib/alex/modelchecking/dao/ModelCheckingConfigDAO.java deleted file mode 100644 index 51e92d4ba..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/dao/ModelCheckingConfigDAO.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.dao; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.modelchecking.entities.LtsFormulaSuite; -import de.learnlib.alex.modelchecking.entities.ModelCheckingConfig; -import de.learnlib.alex.modelchecking.repositories.LtsFormulaSuiteRepository; -import de.learnlib.alex.modelchecking.repositories.ModelCheckingConfigRepository; -import java.util.List; -import java.util.stream.Collectors; -import org.hibernate.Hibernate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(rollbackFor = Exception.class) -public class ModelCheckingConfigDAO { - - private final LtsFormulaSuiteDAO formulaSuiteDAO; - private final ProjectRepository projectRepository; - private final LtsFormulaSuiteRepository ltsFormulaSuiteRepository; - private final ModelCheckingConfigRepository modelCheckingConfigRepository; - - @Autowired - public ModelCheckingConfigDAO( - LtsFormulaSuiteDAO formulaSuiteDAO, - LtsFormulaSuiteRepository ltsFormulaSuiteRepository, - ModelCheckingConfigRepository modelCheckingConfigRepository, - ProjectRepository projectRepository - ) { - this.formulaSuiteDAO = formulaSuiteDAO; - this.ltsFormulaSuiteRepository = ltsFormulaSuiteRepository; - this.modelCheckingConfigRepository = modelCheckingConfigRepository; - this.projectRepository = projectRepository; - } - - public ModelCheckingConfig create(User user, Long projectId, ModelCheckingConfig config) { - final var formulaSuites = getFormulaSuites(user, projectId, config); - - final var configToCreate = new ModelCheckingConfig(); - configToCreate.setMinUnfolds(config.getMinUnfolds()); - configToCreate.setMultiplier(config.getMultiplier()); - configToCreate.setFormulaSuites(formulaSuites); - - final var createdConfig = modelCheckingConfigRepository.save(configToCreate); - loadLazyRelations(createdConfig); - - return createdConfig; - } - - public ModelCheckingConfig update(User user, Long projectId, Long configId, ModelCheckingConfig config) { - final var configInDB = modelCheckingConfigRepository.findById(configId) - .orElseThrow(() -> new NotFoundException("The config could not be found.")); - - final var formulaSuites = getFormulaSuites(user, projectId, config); - - configInDB.setFormulaSuites(formulaSuites); - configInDB.setMultiplier(config.getMultiplier()); - configInDB.setMinUnfolds(config.getMinUnfolds()); - - final var updatedConfig = modelCheckingConfigRepository.save(configInDB); - loadLazyRelations(updatedConfig); - - return updatedConfig; - } - - private List getFormulaSuites(User user, Long projectId, ModelCheckingConfig config) { - final var project = projectRepository.findById(projectId).orElse(null); - - final var formulaSuites = ltsFormulaSuiteRepository.findAllById(config.getFormulaSuites().stream() - .map(LtsFormulaSuite::getId) - .collect(Collectors.toSet()) - ); - - for (var fs : formulaSuites) { - formulaSuiteDAO.checkAccess(user, project, fs); - } - - return formulaSuites; - } - - public void loadLazyRelations(ModelCheckingConfig config) { - Hibernate.initialize(config.getFormulaSuites()); - config.getFormulaSuites().forEach(formulaSuiteDAO::loadLazyRelations); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/dao/ModelCheckingResultDAO.java b/backend/src/main/java/de/learnlib/alex/modelchecking/dao/ModelCheckingResultDAO.java deleted file mode 100644 index b6088213f..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/dao/ModelCheckingResultDAO.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.dao; - -import de.learnlib.alex.modelchecking.entities.ModelCheckingResult; -import de.learnlib.alex.modelchecking.repositories.ModelCheckingResultRepository; -import java.util.List; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(rollbackFor = Exception.class) -public class ModelCheckingResultDAO { - - private final ModelCheckingResultRepository modelCheckingResultRepository; - - @Autowired - public ModelCheckingResultDAO(ModelCheckingResultRepository modelCheckingResultRepository) { - this.modelCheckingResultRepository = modelCheckingResultRepository; - } - - public ModelCheckingResult create(ModelCheckingResult result) { - return modelCheckingResultRepository.save(result); - } - - public List create(List results) { - return modelCheckingResultRepository.saveAll(results); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/entities/LtsCheckingConfig.java b/backend/src/main/java/de/learnlib/alex/modelchecking/entities/LtsCheckingConfig.java deleted file mode 100644 index 5615a62f2..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/entities/LtsCheckingConfig.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.entities; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import javax.validation.ValidationException; - -/** Configuration object for checking lts properties on a learned model. */ -public class LtsCheckingConfig { - - /** The test number of the learner result. */ - private Long learnerResultId; - - /** The step number in the result. */ - private Integer stepNo; - - /** The formulas to check. */ - private List formulas; - - /** The IDs of the formulas to check. */ - private List formulaIds; - - /** How many unfolds are used for checking. */ - private Integer minUnfolds; - - /** The multiplier > 0. */ - private Double multiplier; - - /** Constructor. */ - public LtsCheckingConfig() { - this.formulas = new ArrayList<>(); - this.formulaIds = new ArrayList<>(); - this.minUnfolds = 0; - this.multiplier = 1.0; - } - - public Long getLearnerResultId() { - return learnerResultId; - } - - public void setLearnerResultId(Long learnerResultId) { - this.learnerResultId = learnerResultId; - } - - public Integer getStepNo() { - return stepNo; - } - - public void setStepNo(Integer stepNo) { - this.stepNo = stepNo; - } - - public List getFormulas() { - return formulas; - } - - public void setFormulas(List formulas) { - this.formulas = Optional.ofNullable(formulas).orElse(new ArrayList<>()); - } - - public Integer getMinUnfolds() { - return minUnfolds; - } - - public void setMinUnfolds(Integer minUnfolds) { - this.minUnfolds = minUnfolds; - } - - public Double getMultiplier() { - return multiplier; - } - - public void setMultiplier(Double multiplier) { - this.multiplier = multiplier; - } - - public List getFormulaIds() { - return formulaIds; - } - - public void setFormulaIds(List formulaIds) { - this.formulaIds = Optional.ofNullable(formulaIds).orElse(new ArrayList<>()); - } - - /** - * Validate the config. - * - * @throws ValidationException - * If the config is not valid. - */ - public void validate() throws ValidationException { - if (learnerResultId == null || learnerResultId < 0) { - throw new ValidationException("The ID of the learner result has to be > 0."); - } else if (stepNo == null || stepNo < 1) { - throw new ValidationException("The step number has to be > 0."); - } else if (formulas.size() + formulaIds.size() == 0) { - throw new ValidationException("There has to be at least one formula."); - } else if (minUnfolds < 0) { - throw new ValidationException("minUnfolds has to be >= 0."); - } else if (multiplier <= 0.0) { - throw new ValidationException("multiplier has to be > 0.0"); - } - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/entities/LtsCheckingResult.java b/backend/src/main/java/de/learnlib/alex/modelchecking/entities/LtsCheckingResult.java deleted file mode 100644 index 7dd9bda84..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/entities/LtsCheckingResult.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.entities; - -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.List; -import net.automatalib.words.Word; - -/** The counterexample of a model check. */ -public class LtsCheckingResult { - - /** The formula that has been checked. */ - private LtsFormula formula; - - /** The ID of the learner result. */ - private Long learnerResultId; - - /** Which hypothesis has been checked. */ - private Long learnerResultStepNo; - - /** The prefix of the counterexample. */ - private List prefix; - - /** The loop part of the counterexample. */ - private List loop; - - /** Constructor. */ - public LtsCheckingResult(LtsFormula formula, Long learnerResultId, Long learnerResultStepNo) { - this(formula, learnerResultId, learnerResultStepNo, Word.epsilon(), Word.epsilon()); - } - - public LtsCheckingResult(LtsFormula formula, Long learnerResultId, Long learnerResultStepNo, Word prefix, Word loop) { - this.formula = formula; - this.learnerResultId = learnerResultId; - this.learnerResultStepNo = learnerResultStepNo; - this.prefix = prefix.asList(); - this.loop = loop.asList(); - } - - public List getPrefix() { - return prefix; - } - - public void setPrefix(List prefix) { - this.prefix = prefix; - } - - public List getLoop() { - return loop; - } - - public void setLoop(List loop) { - this.loop = loop; - } - - public LtsFormula getFormula() { - return formula; - } - - public void setFormula(LtsFormula formula) { - this.formula = formula; - } - - public Long getLearnerResultId() { - return learnerResultId; - } - - public void setLearnerResultId(Long learnerResultId) { - this.learnerResultId = learnerResultId; - } - - public Long getLearnerResultStepNo() { - return learnerResultStepNo; - } - - public void setLearnerResultStepNo(Long learnerResultStepNo) { - this.learnerResultStepNo = learnerResultStepNo; - } - - /** - * Check if the model checker could find a counterexample. - * - * @return True if no counterexample could be found - */ - @JsonProperty("passed") - public boolean isPassed() { - return this.prefix.isEmpty() && this.loop.isEmpty(); - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/entities/LtsFormula.java b/backend/src/main/java/de/learnlib/alex/modelchecking/entities/LtsFormula.java deleted file mode 100644 index 718325220..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/entities/LtsFormula.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.io.Serializable; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.validation.constraints.NotBlank; - -/** - * Entity for a LtsMin LTL formula. - */ -@Entity -public class LtsFormula implements Serializable { - - private static final long serialVersionUID = -5978527026208231972L; - - /** The ID of the formula in the database. */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - /** The project. */ - @JsonIgnore - @ManyToOne( - optional = false - ) - @JoinColumn(name = "suiteId") - private LtsFormulaSuite suite; - - /** The formula. */ - @Column(columnDefinition = "TEXT") - private String name; - - /** The formula. */ - @NotBlank - @Column(columnDefinition = "TEXT") - private String formula; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public LtsFormulaSuite getSuite() { - return suite; - } - - public void setSuite(LtsFormulaSuite suite) { - this.suite = suite; - } - - @JsonProperty("suite") - public Long getSuiteId() { - return suite == null ? null : suite.getId(); - } - - @JsonProperty("suite") - public void setSuiteId(Long suiteId) { - this.suite = new LtsFormulaSuite(); - this.suite.setId(suiteId); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getFormula() { - return formula; - } - - public void setFormula(String formula) { - this.formula = formula == null ? "" : formula; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/entities/LtsFormulaSuite.java b/backend/src/main/java/de/learnlib/alex/modelchecking/entities/LtsFormulaSuite.java deleted file mode 100644 index 6f700ce50..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/entities/LtsFormulaSuite.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import de.learnlib.alex.data.entities.Project; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import javax.persistence.CascadeType; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.validation.constraints.NotEmpty; - -@Entity -public class LtsFormulaSuite implements Serializable { - - private static final long serialVersionUID = -7231689556807426040L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @NotEmpty - private String name; - - @OneToMany( - cascade = CascadeType.REMOVE, - mappedBy = "suite" - ) - private List formulas; - - @ManyToOne( - optional = false - ) - @JoinColumn(name = "projectId") - @JsonIgnore - private Project project; - - public LtsFormulaSuite() { - this.formulas = new ArrayList<>(); - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public List getFormulas() { - return formulas; - } - - public void setFormulas(List formulas) { - this.formulas = formulas; - } - - public Project getProject() { - return project; - } - - public void setProject(Project project) { - this.project = project; - } - - @JsonProperty("project") - public Long getProjectId() { - return project == null ? null : project.getId(); - } - - @JsonProperty("project") - public void setProjectId(Long projectId) { - this.project = new Project(projectId); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/entities/ModelCheckingConfig.java b/backend/src/main/java/de/learnlib/alex/modelchecking/entities/ModelCheckingConfig.java deleted file mode 100644 index 5af240f7b..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/entities/ModelCheckingConfig.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.entities; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.ManyToMany; -import javax.validation.constraints.DecimalMin; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; - -@Entity -public class ModelCheckingConfig implements Serializable { - - private static final long serialVersionUID = 8982283686107232388L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @NotNull - @ManyToMany - private List formulaSuites; - - @NotNull - @Min(1) - private Integer minUnfolds; - - @NotNull - @DecimalMin("0.1") - private Double multiplier; - - public ModelCheckingConfig() { - this.formulaSuites = new ArrayList<>(); - this.minUnfolds = 1; - this.multiplier = 0.1; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public List getFormulaSuites() { - return formulaSuites; - } - - public void setFormulaSuites(List formulaSuites) { - this.formulaSuites = formulaSuites; - } - - public Integer getMinUnfolds() { - return minUnfolds; - } - - public void setMinUnfolds(Integer minUnfolds) { - this.minUnfolds = minUnfolds; - } - - public Double getMultiplier() { - return multiplier; - } - - public void setMultiplier(Double multiplier) { - this.multiplier = multiplier; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof ModelCheckingConfig)) { - return false; - } - ModelCheckingConfig that = (ModelCheckingConfig) o; - return id.equals(that.id) - && minUnfolds.equals(that.minUnfolds) - && multiplier.equals(that.multiplier); - } - - @Override - public int hashCode() { - return Objects.hash(id, minUnfolds, multiplier); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/entities/ModelCheckingResult.java b/backend/src/main/java/de/learnlib/alex/modelchecking/entities/ModelCheckingResult.java deleted file mode 100644 index cd76377c5..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/entities/ModelCheckingResult.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import de.learnlib.alex.data.entities.BaseEntity; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.OneToOne; -import javax.persistence.Transient; -import org.hibernate.annotations.Type; - -@Entity -public class ModelCheckingResult extends BaseEntity implements Serializable { - - private static final long serialVersionUID = 6775415609263387261L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @JsonIgnore - protected Long id; - - @OneToOne - private LtsFormula formula; - - /** The prefix of the counterexample. */ - @Type(type = "list-array") - @Column(columnDefinition = "text[]") - @Basic(fetch = FetchType.EAGER) - private List prefix; - - /** The loop part of the counterexample. */ - @Type(type = "list-array") - @Column(columnDefinition = "text[]") - @Basic(fetch = FetchType.EAGER) - private List loop; - - public ModelCheckingResult() { - this.prefix = new ArrayList<>(); - this.loop = new ArrayList<>(); - } - - public LtsFormula getFormula() { - return formula; - } - - public void setFormula(LtsFormula formula) { - this.formula = formula; - } - - public List getPrefix() { - return prefix; - } - - public void setPrefix(List prefix) { - this.prefix = prefix; - } - - public List getLoop() { - return loop; - } - - public void setLoop(List loop) { - this.loop = loop; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - @JsonProperty("passed") - @Transient - public boolean isPassed() { - return this.prefix.isEmpty() && this.loop.isEmpty(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof ModelCheckingResult)) { - return false; - } - ModelCheckingResult that = (ModelCheckingResult) o; - return id.equals(that.id); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/entities/export/LtsFormulaSuitesExportableEntity.java b/backend/src/main/java/de/learnlib/alex/modelchecking/entities/export/LtsFormulaSuitesExportableEntity.java deleted file mode 100644 index b3985d779..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/entities/export/LtsFormulaSuitesExportableEntity.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.entities.export; - -import com.fasterxml.jackson.databind.JsonNode; -import de.learnlib.alex.data.entities.export.ExportableEntity; - -public class LtsFormulaSuitesExportableEntity extends ExportableEntity { - - private JsonNode formulaSuites; - - public LtsFormulaSuitesExportableEntity(String version, JsonNode formulaSuites) { - super(version, "formulaSuites"); - this.formulaSuites = formulaSuites; - } - - public JsonNode getFormulaSuites() { - return formulaSuites; - } - - public void setFormulaSuites(JsonNode formulaSuites) { - this.formulaSuites = formulaSuites; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/events/ModelCheckerEvent.java b/backend/src/main/java/de/learnlib/alex/modelchecking/events/ModelCheckerEvent.java deleted file mode 100644 index 16d3d51b5..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/events/ModelCheckerEvent.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.events; - -import de.learnlib.alex.modelchecking.entities.LtsCheckingResult; -import de.learnlib.alex.modelchecking.entities.LtsFormula; -import de.learnlib.alex.webhooks.entities.Event; -import de.learnlib.alex.webhooks.entities.EventType; -import java.util.List; - -/** Events for model checking. */ -public class ModelCheckerEvent { - - public static class Created extends Event { - public Created(LtsFormula formula) { - super(formula, EventType.LTS_FORMULA_CREATED); - } - } - - public static class Updated extends Event { - public Updated(LtsFormula formula) { - super(formula, EventType.LTS_FORMULA_UPDATED); - } - } - - public static class Deleted extends Event { - public Deleted(Long id) { - super(id, EventType.LTS_FORMULA_DELETED); - } - } - - public static class DeletedMany extends Event> { - public DeletedMany(List ids) { - super(ids, EventType.LTS_FORMULAS_DELETED); - } - } - - public static class CheckedMany extends Event> { - public CheckedMany(List results) { - super(results, EventType.LTS_FORMULAS_CHECKED); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/repositories/LtsFormulaRepository.java b/backend/src/main/java/de/learnlib/alex/modelchecking/repositories/LtsFormulaRepository.java deleted file mode 100644 index 4259933f2..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/repositories/LtsFormulaRepository.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.repositories; - -import de.learnlib.alex.modelchecking.entities.LtsFormula; -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** Repository for lts formulas. */ -@Repository -public interface LtsFormulaRepository extends JpaRepository { - - List findAllBySuite_IdAndIdIn(Long suiteId, List formulaIds); - - List findAllByIdIn(List formulaIds); -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/repositories/LtsFormulaSuiteRepository.java b/backend/src/main/java/de/learnlib/alex/modelchecking/repositories/LtsFormulaSuiteRepository.java deleted file mode 100644 index 24b9f25de..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/repositories/LtsFormulaSuiteRepository.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.repositories; - -import de.learnlib.alex.modelchecking.entities.LtsFormulaSuite; -import java.util.List; -import java.util.Set; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface LtsFormulaSuiteRepository extends JpaRepository { - - List findAllByProject_Id(Long projectId); - - List findAllByProject_IdAndNameIn(Long projectId, Set names); - - LtsFormulaSuite findByProject_IdAndName(Long projectId, String name); -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/repositories/ModelCheckingConfigRepository.java b/backend/src/main/java/de/learnlib/alex/modelchecking/repositories/ModelCheckingConfigRepository.java deleted file mode 100644 index be5d6ce63..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/repositories/ModelCheckingConfigRepository.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.repositories; - -import de.learnlib.alex.modelchecking.entities.ModelCheckingConfig; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface ModelCheckingConfigRepository extends JpaRepository { -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/repositories/ModelCheckingResultRepository.java b/backend/src/main/java/de/learnlib/alex/modelchecking/repositories/ModelCheckingResultRepository.java deleted file mode 100644 index 9260152f2..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/repositories/ModelCheckingResultRepository.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.repositories; - -import de.learnlib.alex.modelchecking.entities.ModelCheckingResult; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface ModelCheckingResultRepository extends JpaRepository { - - Long deleteAllByFormula_Id(Long formulaId); -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/rest/LtsFormulaResource.java b/backend/src/main/java/de/learnlib/alex/modelchecking/rest/LtsFormulaResource.java deleted file mode 100644 index bfb43b1e2..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/rest/LtsFormulaResource.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.rest; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.modelchecking.dao.LtsFormulaDAO; -import de.learnlib.alex.modelchecking.entities.LtsFormula; -import de.learnlib.alex.modelchecking.entities.LtsFormulaSuite; -import de.learnlib.alex.modelchecking.events.ModelCheckerEvent; -import de.learnlib.alex.security.AuthContext; -import de.learnlib.alex.webhooks.services.WebhookService; -import java.util.Collections; -import java.util.List; -import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/rest/projects/{projectId}/ltsFormulaSuites/{suiteId}/ltsFormulas") -public class LtsFormulaResource { - - private final AuthContext authContext; - private final LtsFormulaDAO ltsFormulaDAO; - private final WebhookService webhookService; - - @Autowired - public LtsFormulaResource(AuthContext authContext, - LtsFormulaDAO ltsFormulaDAO, - WebhookService webhookService) { - this.authContext = authContext; - this.ltsFormulaDAO = ltsFormulaDAO; - this.webhookService = webhookService; - } - - @PostMapping( - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity create(@PathVariable("projectId") Long projectId, - @PathVariable("suiteId") Long suiteId, - @RequestBody LtsFormula formula) { - final User user = authContext.getUser(); - final LtsFormula createdFormula = ltsFormulaDAO.create(user, projectId, suiteId, formula); - webhookService.fireEvent(user, new ModelCheckerEvent.Created(createdFormula)); - return ResponseEntity.status(HttpStatus.CREATED).body(createdFormula); - } - - /** - * Updates an existing formula. - * - * @param projectId - * The ID of the project. - * @param formulaId - * The ID of the formula to update. - * @param formula - * The updated formula object. - * @return Status 200 and the updated formula. - */ - @PutMapping( - value = "/{formulaId}", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity update(@PathVariable("projectId") Long projectId, - @PathVariable("suiteId") Long suiteId, - @PathVariable("formulaId") Long formulaId, - @RequestBody LtsFormula formula) { - final User user = authContext.getUser(); - final LtsFormula updatedFormula = ltsFormulaDAO.update(user, projectId, suiteId, formula); - webhookService.fireEvent(user, new ModelCheckerEvent.Updated(updatedFormula)); - return ResponseEntity.ok(updatedFormula); - } - - @PutMapping( - value = "/batch/{formulaIds}/suite", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> updateSuite(@PathVariable("projectId") Long projectId, - @PathVariable("suiteId") Long suiteId, - @PathVariable("formulaIds") List formulaIds, - @RequestBody LtsFormulaSuite suite) { - final User user = authContext.getUser(); - final List updatedFormulas = ltsFormulaDAO.updateParent(user, projectId, suiteId, formulaIds, suite); - return ResponseEntity.ok(updatedFormulas); - } - - @PutMapping( - value = "/{formulaId}/suite", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity updateSuite(@PathVariable("projectId") Long projectId, - @PathVariable("suiteId") Long suiteId, - @PathVariable("formulaId") Long formulaId, - @RequestBody LtsFormulaSuite suite) { - final var user = authContext.getUser(); - final var updatedFormulas = ltsFormulaDAO.updateParent(user, projectId, suiteId, Collections.singletonList(formulaId), suite); - return ResponseEntity.ok(updatedFormulas.get(0)); - } - - /** - * Delete a formula. - * - * @param projectId - * The ID of the project. - * @param formulaId - * The ID of the formula to delete. - * @return Status 204 on success. - */ - @DeleteMapping( - value = "/{formulaId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity delete(@PathVariable("projectId") Long projectId, - @PathVariable("suiteId") Long suiteId, - @PathVariable("formulaId") Long formulaId) { - final User user = authContext.getUser(); - ltsFormulaDAO.delete(user, projectId, suiteId, formulaId); - webhookService.fireEvent(user, new ModelCheckerEvent.Deleted(formulaId)); - return ResponseEntity.noContent().build(); - } - - /** - * Delete multiple formulas at once. - * - * @param projectId - * The ID of the project. - * @param formulaIds - * The IDs of the formulas to delete. - * @return Status 204 on success. - */ - @DeleteMapping( - value = "/batch/{formulaIds}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity delete(@PathVariable("projectId") Long projectId, - @PathVariable("suiteId") Long suiteId, - @PathVariable("formulaIds") List formulaIds) { - final User user = authContext.getUser(); - ltsFormulaDAO.delete(user, projectId, suiteId, formulaIds); - webhookService.fireEvent(user, new ModelCheckerEvent.DeletedMany(formulaIds)); - return ResponseEntity.noContent().build(); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/rest/LtsFormulaSuiteResource.java b/backend/src/main/java/de/learnlib/alex/modelchecking/rest/LtsFormulaSuiteResource.java deleted file mode 100644 index 5b725f28c..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/rest/LtsFormulaSuiteResource.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.rest; - -import de.learnlib.alex.modelchecking.dao.LtsFormulaSuiteDAO; -import de.learnlib.alex.modelchecking.entities.LtsFormulaSuite; -import de.learnlib.alex.security.AuthContext; -import java.util.List; -import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** The lts formula endpoints for the REST API. */ -@RestController -@Transactional(rollbackFor = Exception.class) -@RequestMapping("/rest/projects/{projectId}/ltsFormulaSuites") -public class LtsFormulaSuiteResource { - - private final AuthContext authContext; - private final LtsFormulaSuiteDAO ltsFormulaSuiteDAO; - - @Autowired - public LtsFormulaSuiteResource(AuthContext authContext, - LtsFormulaSuiteDAO ltsFormulaSuiteDAO) { - this.authContext = authContext; - this.ltsFormulaSuiteDAO = ltsFormulaSuiteDAO; - } - - @GetMapping( - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> getAll(@PathVariable("projectId") Long projectId) { - final var user = authContext.getUser(); - final var suites = ltsFormulaSuiteDAO.getAll(user, projectId); - return ResponseEntity.ok(suites); - } - - @GetMapping( - value = "/{suiteId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity get(@PathVariable("projectId") Long projectId, - @PathVariable("suiteId") Long suiteId) { - final var user = authContext.getUser(); - final var suite = ltsFormulaSuiteDAO.get(user, projectId, suiteId); - return ResponseEntity.ok(suite); - } - - @PostMapping( - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity create(@PathVariable("projectId") Long projectId, - @RequestBody LtsFormulaSuite suite) { - final var user = authContext.getUser(); - final var createdSuite = ltsFormulaSuiteDAO.create(user, projectId, suite); - return ResponseEntity.status(HttpStatus.CREATED).body(createdSuite); - } - - @PutMapping( - value = "/{suiteId}", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity update(@PathVariable("projectId") Long projectId, - @PathVariable("suiteId") Long suiteId, - @RequestBody LtsFormulaSuite suite) { - final var user = authContext.getUser(); - final var updatedSuite = ltsFormulaSuiteDAO.update(user, projectId, suiteId, suite); - return ResponseEntity.ok(updatedSuite); - } - - @DeleteMapping( - value = "/{suiteId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity delete(@PathVariable("projectId") Long projectId, - @PathVariable("suiteId") Long suiteId) { - final var user = authContext.getUser(); - ltsFormulaSuiteDAO.delete(user, projectId, suiteId); - return ResponseEntity.noContent().build(); - } - - @DeleteMapping( - value = "/batch/{suiteIds}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity delete(@PathVariable("projectId") Long projectId, - @PathVariable("suiteIds") List suiteIds) { - final var user = authContext.getUser(); - ltsFormulaSuiteDAO.delete(user, projectId, suiteIds); - return ResponseEntity.noContent().build(); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/rest/ModelCheckerResource.java b/backend/src/main/java/de/learnlib/alex/modelchecking/rest/ModelCheckerResource.java deleted file mode 100644 index 5996aced1..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/rest/ModelCheckerResource.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.rest; - -import de.learnlib.alex.modelchecking.entities.LtsCheckingConfig; -import de.learnlib.alex.modelchecking.entities.ModelCheckingResult; -import de.learnlib.alex.modelchecking.services.ModelCheckerService; -import de.learnlib.alex.security.AuthContext; -import java.util.List; -import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/rest/projects/{projectId}/modelChecker") -public class ModelCheckerResource { - - private final AuthContext authContext; - private final ModelCheckerService modelCheckerService; - - @Autowired - public ModelCheckerResource( - AuthContext authContext, - ModelCheckerService modelCheckerService - ) { - this.authContext = authContext; - this.modelCheckerService = modelCheckerService; - } - - @PostMapping( - value = "/check", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> check( - @PathVariable("projectId") Long projectId, - @RequestBody LtsCheckingConfig config - ) { - final var user = authContext.getUser(); - final var results = modelCheckerService.check(user, projectId, config); - return ResponseEntity.ok(results); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/services/ModelCheckerService.java b/backend/src/main/java/de/learnlib/alex/modelchecking/services/ModelCheckerService.java deleted file mode 100644 index 680847243..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/services/ModelCheckerService.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.services; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.learning.dao.LearnerResultDAO; -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.learning.entities.LearnerResultStep; -import de.learnlib.alex.modelchecking.dao.LtsFormulaDAO; -import de.learnlib.alex.modelchecking.dao.ModelCheckingResultDAO; -import de.learnlib.alex.modelchecking.entities.LtsCheckingConfig; -import de.learnlib.alex.modelchecking.entities.LtsFormula; -import de.learnlib.alex.modelchecking.entities.LtsFormulaSuite; -import de.learnlib.alex.modelchecking.entities.ModelCheckingConfig; -import de.learnlib.alex.modelchecking.entities.ModelCheckingResult; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.function.Function; -import java.util.stream.Collectors; -import net.automatalib.automata.transducers.impl.compact.CompactMealy; -import net.automatalib.modelcheckers.ltsmin.LTSminLTLParser; -import net.automatalib.modelcheckers.ltsmin.ltl.LTSminLTLIO; -import net.automatalib.modelcheckers.ltsmin.ltl.LTSminLTLIOBuilder; -import net.automatalib.words.Alphabet; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -/** Service that is used to execute model checks on learned models. */ -@Service -public class ModelCheckerService { - - private final LearnerResultDAO learnerResultDAO; - private final LtsFormulaDAO ltsFormulaDAO; - private final ModelCheckingResultDAO modelCheckingResultDAO; - - @Autowired - public ModelCheckerService(LearnerResultDAO learnerResultDAO, - LtsFormulaDAO ltsFormulaDAO, - ModelCheckingResultDAO modelCheckingResultDAO) { - this.learnerResultDAO = learnerResultDAO; - this.ltsFormulaDAO = ltsFormulaDAO; - this.modelCheckingResultDAO = modelCheckingResultDAO; - } - - public List check(LearnerResultStep step, ModelCheckingConfig config) { - final var alphabet = step.getHypothesis().createAlphabet(); - final var hypothesis = step.getHypothesis().createMealyMachine(alphabet); - - final var formulas = config.getFormulaSuites().stream() - .map(LtsFormulaSuite::getFormulas) - .flatMap(Collection::stream) - .collect(Collectors.toList()); - - final var results = check(hypothesis, alphabet, formulas, config.getMinUnfolds(), config.getMultiplier()); - return modelCheckingResultDAO.create(results); - } - - /** - * Check formulas against a learned model in a learner result. - * - * @param user - * The user. - * @param projectId - * The ID of the project. - * @param config - * The configuration to use for checking. - * @return A map of possible counterexample (formulaId -> counterexample). - * @throws NotFoundException - * If the project or a lts formula could not be found. - */ - public List check(User user, Long projectId, LtsCheckingConfig config) throws NotFoundException { - for (LtsFormula formula : config.getFormulas()) { - if (!LTSminLTLParser.isValidIOFormula(formula.getFormula())) { - throw new IllegalArgumentException("Formula '" + formula.getFormula() + "' is not formatted correctly"); - } - } - - final List formulasToCheck = new ArrayList<>(config.getFormulas()); - formulasToCheck.addAll(ltsFormulaDAO.getByIds(user, projectId, config.getFormulaIds())); - - final LearnerResult learnerResult = learnerResultDAO.getByTestNo(user, projectId, config.getLearnerResultId()); - final LearnerResultStep step = learnerResult.getSteps().get(config.getStepNo() - 1); - - final Alphabet alphabet = step.getHypothesis().createAlphabet(); - final CompactMealy hypothesis = step.getHypothesis().createMealyMachine(alphabet); - - return check(hypothesis, alphabet, formulasToCheck, config.getMinUnfolds(), config.getMultiplier()); - } - - private List check( - CompactMealy model, - Alphabet alphabet, - List formulas, - int minUnfolds, - double multiplier - ) { - final LTSminLTLIO ltsmin = new LTSminLTLIOBuilder() - .withString2Input(Function.identity()) - .withString2Output(Function.identity()) - .withMinimumUnfolds(minUnfolds) - .withMultiplier(multiplier) - .create(); - - return formulas.stream().map(f -> { - final var ce = ltsmin.findCounterExample(model, alphabet, f.getFormula()); - final var result = new ModelCheckingResult(); - result.setFormula(f); - if (ce != null) { - result.setPrefix(ce.getPrefix().asList()); - result.setLoop(ce.getLoop().asList()); - } - return result; - }).collect(Collectors.toList()); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/services/export/LtsFormulaSuitesExporter.java b/backend/src/main/java/de/learnlib/alex/modelchecking/services/export/LtsFormulaSuitesExporter.java deleted file mode 100644 index 0e492e672..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/services/export/LtsFormulaSuitesExporter.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.services.export; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.entities.export.ExportableEntity; -import de.learnlib.alex.data.services.export.EntityExporter; -import de.learnlib.alex.modelchecking.dao.LtsFormulaSuiteDAO; -import de.learnlib.alex.modelchecking.entities.LtsFormula; -import de.learnlib.alex.modelchecking.entities.LtsFormulaSuite; -import de.learnlib.alex.modelchecking.entities.export.LtsFormulaSuitesExportableEntity; -import java.util.List; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Service -public class LtsFormulaSuitesExporter extends EntityExporter { - - @Autowired - private LtsFormulaSuiteDAO ltsFormulaSuiteDAO; - - public LtsFormulaSuitesExporter() { - om.addMixIn(LtsFormulaSuite.class, IgnoreFieldsForLtsFormulaSuiteMixin.class); - om.addMixIn(LtsFormula.class, IgnoreFieldsForLtsFormulaMixin.class); - } - - public ExportableEntity export(User user, Long projectId) throws Exception { - final List suites = ltsFormulaSuiteDAO.getAll(user, projectId); - return new LtsFormulaSuitesExportableEntity( - version, - om.readTree(om.writeValueAsString(suites)) - ); - } - - public abstract static class IgnoreFieldsForLtsFormulaSuiteMixin extends IgnoreIdFieldMixin { - @JsonIgnore - abstract Long getProjectId(); - } - - public abstract static class IgnoreFieldsForLtsFormulaMixin extends IgnoreIdFieldMixin { - @JsonIgnore - abstract Long getSuiteId(); - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/modelchecking/services/reporters/JUnitModelCheckingResultReporter.java b/backend/src/main/java/de/learnlib/alex/modelchecking/services/reporters/JUnitModelCheckingResultReporter.java deleted file mode 100644 index afbdc840b..000000000 --- a/backend/src/main/java/de/learnlib/alex/modelchecking/services/reporters/JUnitModelCheckingResultReporter.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.services.reporters; - -import de.learnlib.alex.learning.entities.LearnerResultStep; -import de.learnlib.alex.modelchecking.entities.LtsFormulaSuite; -import de.learnlib.alex.modelchecking.entities.ModelCheckingResult; -import java.io.StringWriter; -import java.util.HashMap; -import java.util.Map; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -public class JUnitModelCheckingResultReporter { - - public String createReport(LearnerResultStep step) { - try { - final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); - final DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); - final Document doc = docBuilder.newDocument(); - - final var testNo = step.getResult().getTestNo(); - final var stepNo = step.getStepNo(); - - // create the root element - final Element rootElement = doc.createElement("testsuites"); - rootElement.setAttribute("name", "MC Report (learn run: " + testNo + ", step: " + stepNo + ")"); - doc.appendChild(rootElement); - - final var idToFormulaSuiteMap = new HashMap(); - final var idToNumTests = new HashMap(); - final var idToNumFailures = new HashMap(); - var totalFailures = 0; - - for (var result : step.getModelCheckingResults()) { - final var suite = result.getFormula().getSuite(); - - idToFormulaSuiteMap.putIfAbsent(suite.getId(), suite); - - idToNumTests.putIfAbsent(suite.getId(), 0); - idToNumTests.put(suite.getId(), idToNumTests.get(suite.getId()) + 1); - - idToNumFailures.putIfAbsent(suite.getId(), 0); - if (!result.isPassed()) { - idToNumFailures.put(suite.getId(), idToNumFailures.get(suite.getId()) + 1); - totalFailures++; - } - } - - // create xml elements for test suites and add them to the root element - final Map testSuiteElements = new HashMap<>(); - idToFormulaSuiteMap.forEach((id, formulaSuite) -> { - final Element el = createTestSuiteElement(doc, formulaSuite, idToNumTests.get(id), idToNumFailures.get(id)); - testSuiteElements.put(id, el); - rootElement.appendChild(el); - }); - - // create xml elements for all test cases and append them to their corresponding test suite element - step.getModelCheckingResults().forEach((result) -> { - final Element el = createTestCaseElement(doc, result); - testSuiteElements.get(result.getFormula().getSuite().getId()).appendChild(el); - }); - - // add the summed up statistics of the report to the root 'testsuites' element - rootElement.setAttribute("tests", String.valueOf(step.getModelCheckingResults().size())); - rootElement.setAttribute("failures", String.valueOf(totalFailures)); - rootElement.setAttribute("time", "n/a"); - - // create the xml - final Transformer transformer = TransformerFactory.newInstance().newTransformer(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - final DOMSource source = new DOMSource(doc); - final StringWriter stringWriter = new StringWriter(); - final StreamResult streamResult = new StreamResult(stringWriter); - transformer.transform(source, streamResult); - - return stringWriter.getBuffer().toString(); - - } catch (Exception e) { - e.printStackTrace(); - return ""; - } - } - - private Element createTestSuiteElement(final Document doc, final LtsFormulaSuite suite, int numTests, int numTestsFailed) { - final Element testSuiteEl = doc.createElement("testsuite"); - testSuiteEl.setAttribute("id", String.valueOf(suite.getId())); - testSuiteEl.setAttribute("name", suite.getName()); - testSuiteEl.setAttribute("tests", String.valueOf(numTests)); - testSuiteEl.setAttribute("failures", String.valueOf(numTestsFailed)); - testSuiteEl.setAttribute("time", "n/a"); - return testSuiteEl; - } - - private Element createTestCaseElement(final Document doc, final ModelCheckingResult result) { - final Element testCaseEl = doc.createElement("testcase"); - testCaseEl.setAttribute("name", result.getFormula().getName()); - testCaseEl.setAttribute("id", String.valueOf(result.getId())); - testCaseEl.setAttribute("time", "n/a"); - - if (!result.isPassed()) { - final Element failureEl = doc.createElement("failure"); - failureEl.setAttribute("message", "prefix: " + result.getPrefix() + ", loop: " + result.getLoop()); - testCaseEl.appendChild(failureEl); - } - - return testCaseEl; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/security/AuthContext.java b/backend/src/main/java/de/learnlib/alex/security/AuthContext.java deleted file mode 100644 index 8f8f72aa2..000000000 --- a/backend/src/main/java/de/learnlib/alex/security/AuthContext.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.security; - -import de.learnlib.alex.auth.entities.User; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.stereotype.Component; - -/** - * Component that makes the user of the current request available for DI. - */ -@Component -public class AuthContext { - - /** - * Get the user of the current request. - * - * @return The user of the current request. - */ - public User getUser() { - return (User) SecurityContextHolder.getContext() - .getAuthentication() - .getPrincipal(); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/security/AuthenticationProvider.java b/backend/src/main/java/de/learnlib/alex/security/AuthenticationProvider.java deleted file mode 100644 index 19acef3ce..000000000 --- a/backend/src/main/java/de/learnlib/alex/security/AuthenticationProvider.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.security; - -import de.learnlib.alex.auth.dao.UserDAO; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.auth.entities.UserRole; -import java.security.Principal; -import java.util.Collections; -import java.util.List; -import java.util.regex.Pattern; -import org.jose4j.jwt.JwtClaims; -import org.jose4j.jwt.NumericDate; -import org.jose4j.jwt.consumer.JwtConsumer; -import org.jose4j.jwt.consumer.JwtConsumerBuilder; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.stereotype.Component; - -@Component -public class AuthenticationProvider { - - /** - * The RegExp to describe a proper formatted 'Authorization' header field. - */ - private static final Pattern PATTERN = Pattern.compile("bearer [a-z0-9-_]+\\.[a-z0-9-_]+\\.[a-z0-9-_]+", - Pattern.CASE_INSENSITIVE); - - /** - * The UserDAO to use. - */ - private final UserDAO userDAO; - - public AuthenticationProvider(UserDAO userDAO) { - this.userDAO = userDAO; - } - - public Principal getAuthentication(String jwt) throws Exception { - User user; - if (jwt != null && PATTERN.matcher(jwt).matches()) { - jwt = jwt.split(" ")[1]; - - // check if the jwt is valid - final JwtConsumer jwtConsumer = new JwtConsumerBuilder() - .setExpectedIssuer("ALEX") - .setVerificationKey(JwtHelper.getKey().getPublicKey()) - .build(); - - // get payload and get user id - // if no exception was throws up to here you can be sure that the jwt has not been modified - // and that the user that send the jwt is the one he seems to be - final JwtClaims claims = jwtConsumer.processToClaims(jwt); - if (NumericDate.now().isAfter(claims.getExpirationTime())) { - throw new Exception(); - } - - final Long userId = (Long) claims.getClaimsMap().get("id"); - user = userDAO.getByID(userId); - } else { - // create guest user - user = new User(); - user.setRole(UserRole.ANONYMOUS); - } - - final List authorities = Collections.singletonList(new SimpleGrantedAuthority(user.getRole().toString())); - - return new UsernamePasswordAuthenticationToken(user, null, authorities); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/security/JwtAuthenticationEntryPoint.java b/backend/src/main/java/de/learnlib/alex/security/JwtAuthenticationEntryPoint.java deleted file mode 100644 index 5b8e9938d..000000000 --- a/backend/src/main/java/de/learnlib/alex/security/JwtAuthenticationEntryPoint.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.security; - -import java.io.IOException; -import java.io.Serializable; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.AuthenticationEntryPoint; -import org.springframework.stereotype.Component; - -@Component -public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable { - - private static final long serialVersionUID = -1401208776276614478L; - - @Override - public void commence(HttpServletRequest request, HttpServletResponse response, - AuthenticationException authException) throws IOException { - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/security/JwtHelper.java b/backend/src/main/java/de/learnlib/alex/security/JwtHelper.java deleted file mode 100644 index c5fdfb81f..000000000 --- a/backend/src/main/java/de/learnlib/alex/security/JwtHelper.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.security; - -import de.learnlib.alex.auth.entities.User; -import org.jose4j.jwk.RsaJsonWebKey; -import org.jose4j.jwk.RsaJwkGenerator; -import org.jose4j.jws.AlgorithmIdentifiers; -import org.jose4j.jws.JsonWebSignature; -import org.jose4j.jwt.JwtClaims; -import org.jose4j.jwt.NumericDate; -import org.jose4j.lang.JoseException; - -/** - * Helper class around the JWTs, including the security aspect. - */ -public final class JwtHelper { - - /** The number of bits used by the JWK lib. */ - public static final int JWK_STRENGTH_IN_BITS = 2048; - - /** - * The RSA public/private key pair. - */ - private static RsaJsonWebKey rsaJsonWebKey; - - - /** - * Default constructor disabled, because this is just a helper class. - */ - private JwtHelper() { - } - - /** - * Get the RSA key pair. - * The method will create a pair, if non exists, i.e. the first call of this method. - * If no pair can be created, it will shutdown the VM because this would mean a hugh security risk. - * - * @return The RSA key pair - */ - public static RsaJsonWebKey getKey() { - if (rsaJsonWebKey == null) { - try { - rsaJsonWebKey = RsaJwkGenerator.generateJwk(JWK_STRENGTH_IN_BITS); - } catch (JoseException e) { - e.printStackTrace(); - System.exit(0); - } - } - - return rsaJsonWebKey; - } - - /** - * Generates a JWT as String representation. - * Encodes the id and the role of the user as "userId" and "userRole" in the claims of the jwt - * - * @param user - * The user to generate the JWT from. - * @return The string representation of the jwt. - * @throws JoseException - * If the Jose library failed to create a JWT token. - */ - public static String generateJWT(User user) throws JoseException { - // generate claims with user data - final JwtClaims claims = new JwtClaims(); - claims.setIssuer("ALEX"); - claims.setGeneratedJwtId(); - claims.setClaim("id", user.getId()); - claims.setClaim("role", user.getRole()); - claims.setClaim("email", user.getEmail()); - claims.setIssuedAt(NumericDate.now()); - - final NumericDate expirationDate = NumericDate.now(); - expirationDate.addSeconds(604800); - claims.setExpirationTime(expirationDate); - - // create signature - final JsonWebSignature jws = new JsonWebSignature(); - jws.setPayload(claims.toJson()); - jws.setKey(getKey().getPrivateKey()); - jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256); - - // return signed jwt - return jws.getCompactSerialization(); - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/security/JwtRequestFilter.java b/backend/src/main/java/de/learnlib/alex/security/JwtRequestFilter.java deleted file mode 100644 index 647ec6a81..000000000 --- a/backend/src/main/java/de/learnlib/alex/security/JwtRequestFilter.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.security; - -import java.io.IOException; -import javax.servlet.FilterChain; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; -import org.springframework.stereotype.Component; -import org.springframework.web.filter.OncePerRequestFilter; - -/** - * Custom Request filter that is executed for each incoming request. - */ -@Component -public class JwtRequestFilter extends OncePerRequestFilter { - - private final AuthenticationProvider authenticationProvider; - - @Autowired - public JwtRequestFilter(AuthenticationProvider authenticationProvider) { - this.authenticationProvider = authenticationProvider; - } - - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) - throws IOException { - try { - final var jwt = request.getHeader(HttpHeaders.AUTHORIZATION); - final var usernamePasswordAuthToken = (UsernamePasswordAuthenticationToken) authenticationProvider.getAuthentication(jwt); - - usernamePasswordAuthToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); - SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthToken); - - filterChain.doFilter(request, response); - } catch (Exception e) { - e.printStackTrace(); - - response.sendError(HttpStatus.UNAUTHORIZED.value(), "You could not be authenticated."); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/security/SecurityConfiguration.java b/backend/src/main/java/de/learnlib/alex/security/SecurityConfiguration.java deleted file mode 100644 index cc787a1e5..000000000 --- a/backend/src/main/java/de/learnlib/alex/security/SecurityConfiguration.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.security; - -import de.learnlib.alex.auth.entities.UserRole; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpMethod; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; - -@Configuration -@EnableWebSecurity -@EnableGlobalMethodSecurity(prePostEnabled = true) -public class SecurityConfiguration extends WebSecurityConfigurerAdapter { - - @Autowired - private JwtRequestFilter jwtRequestFilter; - - @Autowired - private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; - - @Override - protected void configure(HttpSecurity httpSecurity) throws Exception { - final String adminAuthority = UserRole.ADMIN.toString(); - final String registeredAuthority = UserRole.REGISTERED.toString(); - - httpSecurity.csrf().disable() - .authorizeRequests() - .antMatchers(HttpMethod.GET, "/rest/settings").permitAll() - .antMatchers(HttpMethod.PUT, "/rest/settings").hasAuthority(adminAuthority) - .antMatchers("/rest/settings/drivers/**").hasAuthority(adminAuthority) - .antMatchers(HttpMethod.POST, "/rest/users/login").permitAll() - .antMatchers(HttpMethod.GET, "/rest/users").hasAuthority(adminAuthority) - .antMatchers(HttpMethod.POST, "/rest/users").permitAll() - .antMatchers(HttpMethod.PUT, "/rest/users/{\\d+}/role").hasAuthority(adminAuthority) - .antMatchers(HttpMethod.PUT, "/rest/users/{\\d+}/processes").hasAuthority(adminAuthority) - .antMatchers(HttpMethod.DELETE, "/rest/users/batch/**").hasAuthority(adminAuthority) - .antMatchers("/rest/ws/stomp/**").permitAll() - .antMatchers("/rest/ws/disconnect").hasAnyAuthority(new String[]{registeredAuthority, adminAuthority}) - .antMatchers("/rest/**").hasAnyAuthority(new String[]{registeredAuthority, adminAuthority}).and() - .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and() - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() - .cors(); - - httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/settings/dao/SettingsDAO.java b/backend/src/main/java/de/learnlib/alex/settings/dao/SettingsDAO.java deleted file mode 100644 index c9ba9eb42..000000000 --- a/backend/src/main/java/de/learnlib/alex/settings/dao/SettingsDAO.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.settings.dao; - -import de.learnlib.alex.settings.entities.DriverSettings; -import de.learnlib.alex.settings.entities.Settings; -import de.learnlib.alex.settings.repositories.SettingsRepository; -import javax.validation.ValidationException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -/** - * Implementation of a SettingsDAO using Spring Data. - */ -@Service -@Transactional(rollbackFor = Exception.class) -public class SettingsDAO { - - /** The SettingsRepository to use. Will be injected. */ - private final SettingsRepository settingsRepository; - - /** - * Creates a new SettingsDAO. - * - * @param settingsRepository - * The SettingsRepository to use. - */ - @Autowired - public SettingsDAO(SettingsRepository settingsRepository) { - this.settingsRepository = settingsRepository; - } - - public void create(Settings settings) { - if (settingsRepository.count() == 1) { - throw new ValidationException("The settings have already been created."); - } - - settingsRepository.save(settings); - updateDriverSystemProperties(settings.getDriverSettings()); - } - - public Settings get() { - return settingsRepository.get(); - } - - public Settings update(Settings settings) { - final var updatedSettings = settingsRepository.save(settings); - updateDriverSystemProperties(settings.getDriverSettings()); - return updatedSettings; - } - - public void updateDriverSystemProperties(DriverSettings driverSettings) { - System.setProperty("webdriver.remote.url", driverSettings.getRemote()); - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/settings/entities/DriverSettings.java b/backend/src/main/java/de/learnlib/alex/settings/entities/DriverSettings.java deleted file mode 100644 index 038b9d702..000000000 --- a/backend/src/main/java/de/learnlib/alex/settings/entities/DriverSettings.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.settings.entities; - -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import java.io.Serializable; -import java.util.Objects; -import javax.persistence.Embeddable; - -/** - * The entity for web driver settings. - */ -@Embeddable -@JsonPropertyOrder(alphabetic = true) -public class DriverSettings implements Serializable { - - /** To be serialized. */ - private static final long serialVersionUID = -4199641230344018378L; - - /** The URL path to the Remote Selenium Server. */ - private String remote; - - /** Constructor. */ - public DriverSettings() { - } - - public String getRemote() { - return remote == null ? "" : remote; - } - - public void setRemote(String remote) { - this.remote = remote; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof DriverSettings)) { - return false; - } - DriverSettings that = (DriverSettings) o; - return Objects.equals(remote, that.remote); - } - - @Override - public int hashCode() { - return Objects.hash(remote); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/settings/entities/Settings.java b/backend/src/main/java/de/learnlib/alex/settings/entities/Settings.java deleted file mode 100644 index 87d29fd31..000000000 --- a/backend/src/main/java/de/learnlib/alex/settings/entities/Settings.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.settings.entities; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import java.io.Serializable; -import java.util.Objects; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.validation.constraints.NotNull; - -/** - * The settings entity. - */ -@Entity -@JsonPropertyOrder(alphabetic = true) -public class Settings implements Serializable { - - /** To be serialized. */ - private static final long serialVersionUID = -4417681626093036478L; - - /** The id of the settings object in the database. */ - @Id - private Long id = 1L; - - /** The settings regarding available web drivers. */ - @Embedded - @NotNull - private DriverSettings driverSettings; - - /** If new users are allowed to create accounts. If false, only admins are allowed to create new users. */ - @NotNull - private boolean allowUserRegistration; - - private String runtime; - - /** Constructor. */ - public Settings() { - this.driverSettings = new DriverSettings(); - this.allowUserRegistration = true; - this.runtime = "kubernetes"; - } - - /** - * Get the driver settings. - * - * @return {@link DriverSettings} - */ - @JsonProperty("driver") - public DriverSettings getDriverSettings() { - return driverSettings; - } - - /** - * Set the id. - * - * @param id - * {@link Settings#id} - */ - public void setId(Long id) { - this.id = id; - } - - /** - * Get the id. - * - * @return {@link Settings#id} - */ - public Long getId() { - return id; - } - - /** - * Set the driver settings. - * - * @param driverSettings - * {@link DriverSettings} - */ - @JsonProperty("driver") - public void setDriverSettings(DriverSettings driverSettings) { - this.driverSettings = driverSettings; - } - - public boolean isAllowUserRegistration() { - return allowUserRegistration; - } - - public void setAllowUserRegistration(boolean allowUserRegistration) { - this.allowUserRegistration = allowUserRegistration; - } - - public String getRuntime() { - return runtime; - } - - public void setRuntime(String runtime) { - this.runtime = runtime; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof Settings)) { - return false; - } - Settings settings = (Settings) o; - return allowUserRegistration == settings.allowUserRegistration - && Objects.equals(id, settings.id) - && Objects.equals(runtime, settings.runtime) - && Objects.equals(driverSettings, settings.driverSettings); - } - - @Override - public int hashCode() { - return Objects.hash(id, driverSettings, runtime, allowUserRegistration); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/settings/events/SettingsEvent.java b/backend/src/main/java/de/learnlib/alex/settings/events/SettingsEvent.java deleted file mode 100644 index 6d8f9bf7b..000000000 --- a/backend/src/main/java/de/learnlib/alex/settings/events/SettingsEvent.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.settings.events; - -import de.learnlib.alex.settings.entities.Settings; -import de.learnlib.alex.webhooks.entities.Event; -import de.learnlib.alex.webhooks.entities.EventType; - -public class SettingsEvent { - - /** Event for when the app settings are updated. */ - public static class Updated extends Event { - - /** - * Constructor. - * - * @param settings - * The updated settings. - */ - public Updated(Settings settings) { - super(settings, EventType.SETTINGS_UPDATED); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/settings/repositories/SettingsRepository.java b/backend/src/main/java/de/learnlib/alex/settings/repositories/SettingsRepository.java deleted file mode 100644 index 0e4dfb9d6..000000000 --- a/backend/src/main/java/de/learnlib/alex/settings/repositories/SettingsRepository.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.settings.repositories; - -import de.learnlib.alex.settings.entities.Settings; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.stereotype.Repository; - -/** - * Repository to persist the Settings. - */ -@Repository -public interface SettingsRepository extends JpaRepository { - - /** - * Get the settings. - * There will be alway only one settings object. - * - * @return The system settings. - */ - @Query("SELECT s FROM Settings s WHERE s.id = 1") - Settings get(); - -} diff --git a/backend/src/main/java/de/learnlib/alex/settings/rest/SettingsResource.java b/backend/src/main/java/de/learnlib/alex/settings/rest/SettingsResource.java deleted file mode 100644 index dcb79bd2d..000000000 --- a/backend/src/main/java/de/learnlib/alex/settings/rest/SettingsResource.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.settings.rest; - -import de.learnlib.alex.settings.dao.SettingsDAO; -import de.learnlib.alex.settings.entities.Settings; -import de.learnlib.alex.settings.events.SettingsEvent; -import de.learnlib.alex.webhooks.services.WebhookService; -import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * REST API to manage the settings. - */ -@RestController -@RequestMapping(value = "/rest/settings") -public class SettingsResource { - - private final SettingsDAO settingsDAO; - private final WebhookService webhookService; - - @Autowired - public SettingsResource(SettingsDAO settingsDAO, WebhookService webhookService) { - this.settingsDAO = settingsDAO; - this.webhookService = webhookService; - } - - /** - * Get get application settings object. - * - * @return The application settings on success. - */ - @GetMapping( - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity get() { - final var settings = settingsDAO.get(); - return ResponseEntity.ok(settings); - } - - /** - * Update the application settings. - * - * @param settings - * The updated settings object. - * @return The updated settings object on success. - */ - @PutMapping( - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity update(@RequestBody Settings settings) { - final var updatedSettings = settingsDAO.update(settings); - webhookService.fireEvent(new SettingsEvent.Updated(settings)); - return ResponseEntity.ok(updatedSettings); - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/dao/TestDAO.java b/backend/src/main/java/de/learnlib/alex/testing/dao/TestDAO.java deleted file mode 100644 index 98403091d..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/dao/TestDAO.java +++ /dev/null @@ -1,635 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.dao; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.EntityLockedException; -import de.learnlib.alex.common.exceptions.ForbiddenOperationException; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.dao.ParameterizedSymbolDAO; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.dao.SymbolDAO; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolInputParameter; -import de.learnlib.alex.data.entities.SymbolOutputMapping; -import de.learnlib.alex.data.entities.SymbolOutputParameter; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.data.utils.SymbolOutputMappingUtils; -import de.learnlib.alex.testing.entities.Test; -import de.learnlib.alex.testing.entities.TestCase; -import de.learnlib.alex.testing.entities.TestCaseResult; -import de.learnlib.alex.testing.entities.TestCaseStep; -import de.learnlib.alex.testing.entities.TestExecutionConfig; -import de.learnlib.alex.testing.entities.TestQueueItem; -import de.learnlib.alex.testing.entities.TestReport; -import de.learnlib.alex.testing.entities.TestResult; -import de.learnlib.alex.testing.entities.TestStatus; -import de.learnlib.alex.testing.entities.TestSuite; -import de.learnlib.alex.testing.repositories.TestCaseStepRepository; -import de.learnlib.alex.testing.repositories.TestExecutionConfigRepository; -import de.learnlib.alex.testing.repositories.TestRepository; -import de.learnlib.alex.testing.repositories.TestResultRepository; -import de.learnlib.alex.testing.services.TestService; -import de.learnlib.alex.websocket.services.TestPresenceService; -import org.apache.shiro.authz.UnauthorizedException; -import org.hibernate.Hibernate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.validation.ValidationException; -import java.time.ZonedDateTime; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** The implementation of the test dao. */ -@Service -@Transactional(rollbackFor = Exception.class) -public class TestDAO { - - private final ProjectDAO projectDAO; - private final SymbolDAO symbolDAO; - private final TestRepository testRepository; - private final ProjectRepository projectRepository; - private final TestCaseStepRepository testCaseStepRepository; - private final ParameterizedSymbolDAO parameterizedSymbolDAO; - private final TestResultRepository testResultRepository; - private final TestPresenceService testPresenceService; - private final TestService testService; - private final TestExecutionConfigRepository testExecutionConfigRepository; - - @Autowired - public TestDAO(ProjectDAO projectDAO, TestRepository testRepository, SymbolDAO symbolDAO, - TestCaseStepRepository testCaseStepRepository, ProjectRepository projectRepository, - ParameterizedSymbolDAO parameterizedSymbolDAO, TestResultRepository testResultRepository, - @Lazy TestPresenceService testPresenceService, @Lazy TestService testService, @Lazy TestExecutionConfigRepository testExecutionConfigRepository) { - this.projectDAO = projectDAO; - this.testRepository = testRepository; - this.symbolDAO = symbolDAO; - this.testCaseStepRepository = testCaseStepRepository; - this.projectRepository = projectRepository; - this.parameterizedSymbolDAO = parameterizedSymbolDAO; - this.testResultRepository = testResultRepository; - this.testPresenceService = testPresenceService; - this.testService = testService; - this.testExecutionConfigRepository = testExecutionConfigRepository; - } - - public Test createByGenerate(User user, Project project, Test test) { - beforeSaving(user, project, test); - if (test instanceof TestCase) { - final TestCase testCase = (TestCase) test; - - final List steps = testCase.getSteps(); - final List preSteps = testCase.getPreSteps(); - final List postSteps = testCase.getPostSteps(); - - testCase.setSteps(new ArrayList<>()); - testCase.setPreSteps(new ArrayList<>()); - testCase.setPostSteps(new ArrayList<>()); - - testRepository.save(test); - - testCase.setSteps(steps); - testCase.setPreSteps(preSteps); - testCase.setPostSteps(postSteps); - - saveTestCaseSteps(testCase.getPreSteps()); - saveTestCaseSteps(testCase.getSteps()); - saveTestCaseSteps(testCase.getPostSteps()); - - testCase.setLastUpdatedBy(user); - } - - return testRepository.save(test); - } - - private Test getParent(User user, Long projectId, Long parentId) { - if (parentId == null) { - return null; - } - - final Test parent = get(user, projectId, parentId); - if (parent instanceof TestCase) { - throw new ValidationException("The parent can only be a Test Suite."); - } - - return parent; - } - - public synchronized Test create(User user, Long projectId, Test test) throws NotFoundException, ValidationException { - test.setId(null); - - final Test root = testRepository.findFirstByProject_IdOrderByIdAsc(projectId); - if (test.getParent() == null) { - test.setParent(root); - } - - // make sure the name of the test case is unique - String name = test.getName(); - int i = 1; - - while (testRepository.findOneByParent_IdAndName(test.getParentId(), name) != null) { - name = test.getName() + " - " + i; - i++; - } - test.setName(name); - - final Project project = projectDAO.getByID(user, projectId); - test.setProject(project); - test.setParent(getParent(user, projectId, test.getParentId())); - - return createByGenerate(user, project, test); - } - - public List create(User user, Long projectId, List tests) { - return create(user, projectId, tests, null); - } - - public List create(User user, Long projectId, List tests, Map configRefMap) { - return create(user, projectId, new ArrayList<>(tests), null, configRefMap); - } - - public List importTests(User user, Long projectId, List tests, Map configRefMap, Map symbolRefMap) { - projectDAO.getByID(user, projectId); - - // fetch symbols and map with oldSymbolIds as keys when a testRefMap is provided - final Map symbolMap = symbolDAO.getAll(user, projectId).stream() - .collect(Collectors.toMap(s -> symbolRefMap != null ? symbolRefMap.get(s.getId()) : s.getId(), Function.identity())); - - mapSymbolsInTests(tests, symbolMap); - - return create(user, projectId, tests, configRefMap); - } - - private void mapSymbolsInTests(List tests, Map symbolMap) { - for (Test test : tests) { - if (test instanceof TestCase) { - final TestCase tc = (TestCase) test; - mapSymbolsInTestCaseSteps(tc.getPreSteps(), symbolMap); - mapSymbolsInTestCaseSteps(tc.getSteps(), symbolMap); - mapSymbolsInTestCaseSteps(tc.getPostSteps(), symbolMap); - } else { - mapSymbolsInTests(((TestSuite) test).getTests(), symbolMap); - } - } - } - - private void mapSymbolsInTestCaseSteps(List steps, Map symbolMap) { - for (TestCaseStep step : steps) { - step.getPSymbol().setSymbol(symbolMap.get(step.getPSymbol().getSymbol().getId())); - } - } - - private List create(User user, Long projectId, List tests, TestSuite parent, Map configRefMap) { - final List createdTests = new ArrayList<>(); - - for (final Test test : tests) { - if (parent != null) { - test.setParent(parent); - } - - if (test instanceof TestCase) { - var refTestId = test.getId(); - Test createdTest = create(user, projectId, test); - if (configRefMap != null) { - configRefMap.put(refTestId, createdTest.getId()); - } - createdTests.add(createdTest); - } else { - final TestSuite testSuite = (TestSuite) test; - final List testsInSuite = testSuite.getTests(); - - testSuite.setTests(new ArrayList<>()); - var refSuiteId = test.getId(); - Test createdTest = create(user, projectId, testSuite); - if (configRefMap != null) { - configRefMap.put(refSuiteId, createdTest.getId()); - } - createdTests.add(createdTest); - create(user, projectId, testsInSuite, testSuite, configRefMap); - } - } - - return createdTests; - } - - public Test get(User user, Long projectId, Long testId) { - final var project = projectRepository.findById(projectId).orElse(null); - final var test = testRepository.findById(testId).orElse(null); - checkAccess(user, project, test); - loadLazyRelations(test); - return test; - } - - public List get(User user, Long projectId, List ids) { - final Project project = projectRepository.findById(projectId).orElse(null); - projectDAO.checkAccess(user, project); - final List tests = testRepository.findAllByProject_IdAndIdIn(projectId, ids); - for (Test t : tests) { - loadLazyRelations(t); - } - return tests; - } - - public Test getRoot(User user, Long projectId) { - final Project project = projectRepository.findById(projectId).orElse(null); - projectDAO.checkAccess(user, project); - - final Test root = testRepository.findFirstByProject_IdOrderByIdAsc(projectId); - loadLazyRelations(root); - - return root; - } - - public Test update(User user, Long projectId, Long testId, Test test) { - final var project = projectRepository.findById(projectId).orElse(null); - final var testInDB = testRepository.findById(testId).orElse(null); - checkAccess(user, project, test); - checkRunningTestProcess(user, project, test); - - // check lock status - testPresenceService.checkLockStatus(projectId, test.getId(), user.getId()); - - // make sure the name of the Test Case is unique - final var testWithSameName = testRepository.findOneByParent_IdAndName(test.getParentId(), test.getName()); - if (testWithSameName != null && !testWithSameName.getId().equals(testInDB.getId())) { - throw new ValidationException("To update a test case or suite its name must be unique within its parent."); - } - - final var rootTestSuite = testRepository.findFirstByProject_IdOrderByIdAsc(test.getProjectId()); - if (test.getId().equals(rootTestSuite.getId()) && !test.getName().equals("Root")) { - throw new ValidationException("The name of the root test suite may not be changed."); - } - - if (testInDB instanceof TestSuite && test instanceof TestSuite) { - final var updatedTestSuite = updateTestSuite((TestSuite) testInDB, (TestSuite) test); - loadLazyRelations(updatedTestSuite); - return updatedTestSuite; - } else if (testInDB instanceof TestCase && test instanceof TestCase) { - final var updatedTestCase = updateTestCase(user, (TestCase) testInDB, (TestCase) test); - loadLazyRelations(updatedTestCase); - return updatedTestCase; - } else { - throw new IllegalStateException("Cannot update a test case with a test suite or vice versa."); - } - } - - private Test updateTestCase(User user, TestCase testCaseInDB, TestCase testCase) { - checkIfOutputMappingNamesAreUnique(testCase); - - testCaseInDB.setName(testCase.getName()); - testCaseInDB.setGenerated(false); - testCaseInDB.setUpdatedOn(ZonedDateTime.now()); - testCaseInDB.setLastUpdatedBy(user); - - testCaseInDB.getPreSteps().clear(); - testCaseInDB.getSteps().clear(); - testCaseInDB.getPostSteps().clear(); - testRepository.save(testCaseInDB); - - testCaseInDB.getPreSteps().addAll(testCase.getPreSteps()); - testCaseInDB.getSteps().addAll(testCase.getSteps()); - testCaseInDB.getPostSteps().addAll(testCase.getPostSteps()); - removeIdsFromSteps(testCaseInDB); - beforeSaving(user, testCaseInDB.getProject(), testCaseInDB); - - saveTestCaseSteps(testCaseInDB.getPreSteps()); - saveTestCaseSteps(testCaseInDB.getSteps()); - saveTestCaseSteps(testCaseInDB.getPostSteps()); - testRepository.save(testCaseInDB); - - return testCaseInDB; - } - - private void removeIdsFromSteps(TestCase testCase) { - Stream.of(testCase.getPreSteps(), testCase.getSteps(), testCase.getPostSteps()) - .flatMap(Collection::stream) - .forEach(s -> { - s.setId(null); - s.getPSymbol().setId(null); - s.getPSymbol().getOutputMappings().forEach(om -> om.setId(null)); - s.getPSymbol().getParameterValues().forEach(om -> om.setId(null)); - }); - } - - private void checkIfOutputMappingNamesAreUnique(TestCase testCase) { - final ArrayList steps = new ArrayList<>(); - steps.addAll(testCase.getPreSteps()); - steps.addAll(testCase.getSteps()); - steps.addAll(testCase.getPostSteps()); - - final ArrayList oms = new ArrayList<>(); - steps.forEach(s -> oms.addAll(s.getPSymbol().getOutputMappings())); - SymbolOutputMappingUtils.checkIfMappedNamesAreUnique(oms); - } - - private Test updateTestSuite(TestSuite testSuiteInDB, TestSuite testSuite) { - testSuiteInDB.setName(testSuite.getName()); - return testRepository.save(testSuiteInDB); - } - - public void delete(User user, Long projectId, Long testId) { - final Project project = projectRepository.findById(projectId).orElse(null); - final Test test = testRepository.findById(testId).orElse(null); - checkAccess(user, project, test); - checkRunningTestProcess(user, project, test); - - // check lock status - testPresenceService.checkLockStatusStrict(projectId, testId, user.getId()); - - // check test configs - if (!testExecutionConfigRepository.findAllByProject_IdAndTest_Id(projectId, testId).isEmpty()) { - throw new ForbiddenOperationException("The test " + test.getName() + " is associated with one or more test configs."); - } - - final Test root = testRepository.findFirstByProject_IdOrderByIdAsc(projectId); - if (root.getId().equals(testId)) { - throw new ValidationException("The root test suite cannot be deleted"); - } - - final Test parent = test.getParent(); - if (parent != null) { - ((TestSuite) parent).getTests().remove(test); - test.setParent(null); - } - - testRepository.delete(test); - } - - public void delete(User user, Long projectId, List ids) { - for (Long id : ids) { - delete(user, projectId, id); - } - } - - public List move(User user, Long projectId, List testIds, Long targetId) { - final Project project = projectRepository.findById(projectId).orElse(null); - final List tests = testRepository.findAllById(testIds); - final Test targetTest = testRepository.findById(targetId).orElse(null); - final Test rootTestSuite = testRepository.findFirstByProject_IdOrderByIdAsc(projectId); - - // validation - checkAccess(user, project, targetTest); - if (targetTest instanceof TestCase) { - throw new ValidationException("The target cannot be a test case."); - } - - final TestSuite target = (TestSuite) targetTest; - checkRunningTestProcess(user, project, target); - - for (Test test : tests) { - checkAccess(user, project, test); - - //check lock status - testPresenceService.checkLockStatusStrict(projectId, test.getId(), user.getId()); - - if (test.getId().equals(rootTestSuite.getId())) { - throw new ValidationException("Cannot move the root test suite."); - } - - if (test.getId().equals(target.getId())) { - throw new ValidationException("A test cannot be a parent of itself."); - } - - if (test instanceof TestSuite && target.isDescendantOf((TestSuite) test)) { - throw new ValidationException("A test suite cannot be moved to one of its descendants."); - } - } - - // update references - for (Test test : tests) { - final TestSuite parent = (TestSuite) test.getParent(); - parent.getTests().remove(test); - testRepository.save(parent); - test.setParent(target); - } - - target.getTests().addAll(tests); - testRepository.save(target); - - final List movedTests = testRepository.saveAll(tests); - movedTests.forEach(this::loadLazyRelations); - - return movedTests; - } - - public List getTestCases(User user, Long projectId, Long testSuiteId) { - final Project project = projectRepository.findById(projectId).orElse(null); - final Test test = testRepository.findById(testSuiteId).orElse(null); - checkAccess(user, project, test); - - if (!(test instanceof TestSuite)) { - throw new ValidationException("The ID has to belong to a test suite."); - } - - final TestSuite testSuite = (TestSuite) test; - final List testCases = new ArrayList<>(); - - final ArrayDeque queue = new ArrayDeque<>(); - queue.add(testSuite); - - while (!queue.isEmpty()) { - final TestSuite currentTestSuite = queue.poll(); - for (Test t : currentTestSuite.getTests()) { - if (t instanceof TestSuite) { - queue.addLast((TestSuite) t); - } else { - loadLazyRelations(t); - testCases.add((TestCase) t); - } - } - } - - return testCases; - } - - public Page getResults(User user, Long projectId, Long testId, Pageable pageable) { - get(user, projectId, testId); - - final Page results = testResultRepository.findAllByTest_IdOrderByTestReport_StartDateDesc(testId, pageable); - results.forEach(this::loadLazyRelations); - - return results; - } - - public void checkAccess(User user, Project project, Test test) { - projectDAO.checkAccess(user, project); - - if (test == null) { - throw new NotFoundException("The test could not be found."); - } - - if (!test.getProject().equals(project)) { - throw new UnauthorizedException("You are not allowed to access the test."); - } - } - - public void checkRunningTestProcess(User user, Project project, Test test) { - if (this.getActiveTests(user, project).stream().anyMatch(t -> t.getId().equals(test.getId()))) { - throw new EntityLockedException("The test is currently used in the active test process."); - } - } - - public Set getActiveTests(User user, Project project) { - Set result = new HashSet<>(); - - TestStatus testStatus = this.testService.getStatus(user, project.getId()); - if (testStatus.isActive()) { - Stream.of(List.of(testStatus.getCurrentTestRun()), testStatus.getTestRunQueue()) - .flatMap(List::stream) - .filter(testQueueItem -> - testQueueItem.getReport().getStatus().equals(TestReport.Status.IN_PROGRESS) - || testQueueItem.getReport().getStatus().equals(TestReport.Status.PENDING)) - .map(TestQueueItem::getConfig) - .map(TestExecutionConfig::getTestIds) - .flatMap(Collection::stream) - .collect(Collectors.toSet()).stream() - .map(testIds -> get(user, project.getId(), testIds)) - .forEach(test -> { - result.add(test); - result.addAll(extractDescendantTests(test)); - result.addAll(extractAncestorTests(test)); - }); - } - - return result; - } - - private Set extractDescendantTests(Test test) { - Set result = new HashSet<>(); - - if (test instanceof TestSuite) { - result.addAll(((TestSuite) test).getTestCases()); - ((TestSuite) test).getTestSuites().forEach(descendant -> { - result.add(descendant); - result.addAll(extractDescendantTests(descendant)); - }); - } - - return result; - } - - private Set extractAncestorTests(Test test) { - Set result = new HashSet<>(); - - Optional.ofNullable(test.getParent()) - .ifPresent(ancestor -> { - result.add(ancestor); - result.addAll(extractAncestorTests(ancestor)); - }); - - return result; - } - - private void saveTestCaseSteps(List steps) { - for (int i = 0; i < steps.size(); i++) { - steps.get(i).setNumber(i); - } - - testCaseStepRepository.saveAll(steps); - - // save the parameter values after the test case step is saved so that - // we won't get an entity detached exception. - steps.forEach(step -> { - - // if a parameter value has no id yet, because it is imported, we have to set the reference - // to the parameter manually. - // name -> parameter - final Map inputMap = step.getPSymbol().getSymbol().getInputs().stream() - .collect(Collectors.toMap(SymbolInputParameter::getName, Function.identity())); - - step.getPSymbol().getParameterValues().forEach(value -> - value.setParameter(inputMap.get(value.getParameter().getName())) - ); - - // do the same for outputs - final Map outputMap = step.getPSymbol().getSymbol().getOutputs().stream() - .collect(Collectors.toMap(SymbolOutputParameter::getName, Function.identity())); - - step.getPSymbol().getOutputMappings().forEach(om -> { - om.setParameter(outputMap.get(om.getParameter().getName())); - }); - - parameterizedSymbolDAO.create(step.getPSymbol()); - }); - } - - private void loadLazyRelations(TestResult testResult) { - if (testResult instanceof TestCaseResult) { - Hibernate.initialize(((TestCaseResult) testResult).getOutputs()); - ((TestCaseResult) testResult).getOutputs().forEach(out -> Hibernate.initialize(out.getSymbol())); - } - } - - private void loadLazyRelations(Test test) { - Hibernate.initialize(test.getProject()); - Hibernate.initialize(test.getProject().getEnvironments()); - - if (test instanceof TestSuite) { - TestSuite testSuite = (TestSuite) test; - Hibernate.initialize(testSuite.getTests()); - testSuite.getTests().forEach(this::loadLazyRelations); - } else if (test instanceof TestCase) { - TestCase testCase = (TestCase) test; - Hibernate.initialize(testCase.getSteps()); - testCase.getSteps().forEach(step -> ParameterizedSymbolDAO.loadLazyRelations((step.getPSymbol()))); - Hibernate.initialize(testCase.getPreSteps()); - testCase.getPreSteps().forEach(step -> ParameterizedSymbolDAO.loadLazyRelations((step.getPSymbol()))); - Hibernate.initialize(testCase.getPostSteps()); - testCase.getPostSteps().forEach(step -> ParameterizedSymbolDAO.loadLazyRelations((step.getPSymbol()))); - Hibernate.initialize(testCase.getLastUpdatedBy()); - } - } - - private void beforeSaving(User user, Project project, Test test) { - if (test instanceof TestSuite) { - TestSuite testSuite = (TestSuite) test; - for (Long testId : testSuite.getTestsAsIds()) { - final var otherTest = testRepository.findById(testId).orElse(null); - checkAccess(user, project, otherTest); - testSuite.addTest(otherTest); - } - } else if (test instanceof TestCase) { - TestCase testCase = (TestCase) test; - - final List steps = new ArrayList<>(); - steps.addAll(testCase.getPreSteps()); - steps.addAll(testCase.getSteps()); - steps.addAll(testCase.getPostSteps()); - - for (TestCaseStep step : steps) { - step.setTestCase(testCase); - final Symbol symbol = symbolDAO.get(user, project, step.getPSymbol().getSymbol().getId()); - step.getPSymbol().setSymbol(symbol); - } - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/dao/TestExecutionConfigDAO.java b/backend/src/main/java/de/learnlib/alex/testing/dao/TestExecutionConfigDAO.java deleted file mode 100644 index 7e930c8d6..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/dao/TestExecutionConfigDAO.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.dao; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.dao.ProjectEnvironmentDAO; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.data.repositories.ProjectEnvironmentRepository; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.learning.entities.WebDriverConfig; -import de.learnlib.alex.testing.entities.Test; -import de.learnlib.alex.testing.entities.TestExecutionConfig; -import de.learnlib.alex.testing.repositories.TestExecutionConfigRepository; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; -import javax.persistence.EntityManager; -import org.apache.shiro.authz.UnauthorizedException; -import org.hibernate.Hibernate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(rollbackFor = Exception.class) -public class TestExecutionConfigDAO { - - private final ProjectDAO projectDAO; - private final ProjectRepository projectRepository; - private final TestExecutionConfigRepository testExecutionConfigRepository; - private final ProjectEnvironmentRepository environmentRepository; - private final ProjectEnvironmentDAO environmentDAO; - private final EntityManager entityManager; - private final TestDAO testDAO; - - @Autowired - public TestExecutionConfigDAO(ProjectDAO projectDAO, - ProjectRepository projectRepository, - TestExecutionConfigRepository testExecutionConfigRepository, - ProjectEnvironmentRepository environmentRepository, - ProjectEnvironmentDAO environmentDAO, - EntityManager entityManager, - TestDAO testDAO) { - this.projectDAO = projectDAO; - this.projectRepository = projectRepository; - this.testExecutionConfigRepository = testExecutionConfigRepository; - this.environmentRepository = environmentRepository; - this.environmentDAO = environmentDAO; - this.entityManager = entityManager; - this.testDAO = testDAO; - } - - public TestExecutionConfig create(User user, Long projectId, TestExecutionConfig config) { - final Project project = projectRepository.findById(projectId).orElse(null); - projectDAO.checkAccess(user, project); - - List tests = new ArrayList<>(); - Optional.ofNullable(config.getTestIds()) - .ifPresent(testIds -> testIds.forEach(testId -> { - tests.add(this.testDAO.get(user, projectId, testId)); - })); - config.setTests(tests); - - final ProjectEnvironment projectUrl = environmentRepository.findById(config.getEnvironmentId()).orElse(null); - environmentDAO.checkAccess(user, project, projectUrl); - - config.setProject(project); - config.setEnvironment(projectUrl); - config.setDefault(false); - - final TestExecutionConfig createdConfig = testExecutionConfigRepository.save(config); - loadLazyRelations(createdConfig); - - return createdConfig; - } - - public List getAll(User user, Long projectId) { - final Project project = projectRepository.findById(projectId).orElse(null); - projectDAO.checkAccess(user, project); - - final List configs = testExecutionConfigRepository.findAllByProject_Id(projectId); - configs.forEach(this::loadLazyRelations); - - return configs; - } - - public TestExecutionConfig get(User user, Long projectId, Long configId) { - final Project project = projectRepository.findById(projectId).orElse(null); - final TestExecutionConfig config = testExecutionConfigRepository.findById(configId).orElse(null); - checkAccess(user, project, config); - - loadLazyRelations(config); - return config; - } - - public void delete(User user, Long projectId, Long configId) { - final Project project = projectRepository.findById(projectId).orElse(null); - final TestExecutionConfig config = testExecutionConfigRepository.findById(configId).orElse(null); - checkAccess(user, project, config); - - testExecutionConfigRepository.deleteById(configId); - } - - public TestExecutionConfig update(User user, Long projectId, Long configId, TestExecutionConfig config) { - final Project project = projectRepository.findById(projectId).orElse(null); - final TestExecutionConfig configInDb = testExecutionConfigRepository.findById(configId).orElse(null); - checkAccess(user, project, configInDb); - - if (config.isDefault()) { - final TestExecutionConfig defaultConfig = testExecutionConfigRepository.findByProject_IdAndIs_Default(projectId); - if (defaultConfig == null) { - configInDb.setDefault(true); - } else { - if (!defaultConfig.equals(configInDb)) { - defaultConfig.setDefault(false); - testExecutionConfigRepository.save(defaultConfig); - configInDb.setDefault(true); - } - } - } - - configInDb.setDriverConfig(config.getDriverConfig()); - configInDb.setEnvironmentId(config.getEnvironmentId()); - configInDb.setName(config.getName()); - configInDb.setDescription(config.getDescription()); - configInDb.setTests(testDAO.get(user, projectId, config.getTestIds())); - - final TestExecutionConfig updatedConfig = testExecutionConfigRepository.save(configInDb); - loadLazyRelations(updatedConfig); - return updatedConfig; - } - - public TestExecutionConfig copy(User user, Long projectId, Long configId) { - final Project project = projectRepository.findById(projectId).orElse(null); - final TestExecutionConfig configInDb = testExecutionConfigRepository.findById(configId).orElse(null); - checkAccess(user, project, configInDb); - - final TestExecutionConfig newConfig = new TestExecutionConfig(); - newConfig.setProject(project); - newConfig.setName(configInDb.getName()); - newConfig.setDescription(configInDb.getDescription()); - newConfig.setEnvironment(configInDb.getEnvironment()); - newConfig.setTests(List.copyOf(configInDb.getTests())); - - final WebDriverConfig webDriverConfig = configInDb.getDriverConfig(); - entityManager.detach(webDriverConfig); - webDriverConfig.setId(null); - newConfig.setDriverConfig(webDriverConfig); - - final TestExecutionConfig copiedConfig = testExecutionConfigRepository.save(newConfig); - loadLazyRelations(newConfig); - return copiedConfig; - } - - public List importTestExecutionConfigs(User user, Project project, List testExecutionConfigs, Map configRefMap) { - testExecutionConfigs.forEach(testExecutionConfig -> { - testExecutionConfig.setProject(projectRepository.getOne(project.getId())); - testExecutionConfig.setEnvironment(environmentRepository.findByProject_IdAndName(project.getId(), testExecutionConfig.getEnvironment().getName())); - testExecutionConfig.setTests(testDAO.get(user, project.getId(), testExecutionConfig.getTestIds().stream().map(configRefMap::get).collect(Collectors.toList()))); - }); - - List importedConfigs = testExecutionConfigRepository.saveAll(testExecutionConfigs); - return importedConfigs; - } - - public void checkAccess(User user, Project project, TestExecutionConfig config) { - projectDAO.checkAccess(user, project); - - if (config == null || config.getProjectId() == null) { - throw new NotFoundException("The config could not be found."); - } - - if (!config.getProjectId().equals(project.getId())) { - throw new UnauthorizedException("You are not allowed to access the config."); - } - } - - private void loadLazyRelations(TestExecutionConfig config) { - Hibernate.initialize(config.getProject()); - Hibernate.initialize(config.getTests()); - Hibernate.initialize(config.getEnvironment()); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/dao/TestReportDAO.java b/backend/src/main/java/de/learnlib/alex/testing/dao/TestReportDAO.java deleted file mode 100644 index afa3b21da..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/dao/TestReportDAO.java +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.dao; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.dao.ProjectEnvironmentDAO; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.testing.entities.TestCaseResult; -import de.learnlib.alex.testing.entities.TestExecutionResult; -import de.learnlib.alex.testing.entities.TestReport; -import de.learnlib.alex.testing.entities.TestReport.Status; -import de.learnlib.alex.testing.entities.TestSuiteResult; -import de.learnlib.alex.testing.repositories.TestReportRepository; -import de.learnlib.alex.testing.repositories.TestResultRepository; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.List; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; -import org.apache.commons.io.FileUtils; -import org.apache.shiro.authz.UnauthorizedException; -import org.hibernate.Hibernate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -/** The implementation of the test report DAO . */ -@Service -@Transactional(rollbackFor = Exception.class) -public class TestReportDAO { - - private final TestReportRepository testReportRepository; - private final TestResultRepository testResultRepository; - private final ProjectRepository projectRepository; - private final ProjectEnvironmentDAO projectEnvironmentDAO; - private final ProjectDAO projectDAO; - private final TestResultDAO testResultDAO; - - @Value("${alex.filesRootDir}") - private String filesRootDir; - - @Autowired - public TestReportDAO( - TestReportRepository testReportRepository, - ProjectRepository projectRepository, - ProjectDAO projectDAO, - ProjectEnvironmentDAO projectEnvironmentDAO, - TestResultRepository testResultRepository, - TestResultDAO testResultDAO - ) { - this.testReportRepository = testReportRepository; - this.projectRepository = projectRepository; - this.projectDAO = projectDAO; - this.projectEnvironmentDAO = projectEnvironmentDAO; - this.testResultRepository = testResultRepository; - this.testResultDAO = testResultDAO; - } - - public TestReport create(User user, Long projectId, TestReport testReport) { - final Project project = projectRepository.findById(projectId).orElse(null); - projectDAO.checkAccess(user, project); - - testReport.setId(null); - testReport.setExecutedBy(user); - testReport.setProject(project); - testReport.getTestResults().forEach((testResult) -> { - testResult.setTestReport(testReport); - testResult.setProject(project); - }); - - final ProjectEnvironment env = projectEnvironmentDAO.getByID(user, testReport.getEnvironment().getId()); - testReport.setEnvironment(env); - - final TestReport createdTestReport = testReportRepository.save(testReport); - loadLazyRelations(createdTestReport); - return createdTestReport; - } - - public List abortActiveTestReports() { - final List pendingReports = testReportRepository.findAllByStatusIn( - Arrays.asList(TestReport.Status.IN_PROGRESS, TestReport.Status.PENDING) - ); - pendingReports.forEach(r -> r.setStatus(TestReport.Status.ABORTED)); - return testReportRepository.saveAll(pendingReports); - } - - public Page getAll(User user, Long projectId, Pageable pageable) { - final Project project = projectRepository.findById(projectId).orElse(null); - projectDAO.checkAccess(user, project); - - final Page testReports = testReportRepository.findAllByProject_Id(projectId, pageable); - testReports.forEach(this::loadLazyRelations); - return testReports; - } - - public TestReport get(User user, Long projectId, Long testReportId) { - final Project project = projectRepository.findById(projectId).orElse(null); - final TestReport testReport = testReportRepository.findById(testReportId).orElse(null); - checkAccess(user, project, testReport); - - loadLazyRelations(testReport); - return testReport; - } - - public TestReport getLatest(User user, Long projectId) { - final Project project = projectRepository.findById(projectId).orElse(null); - projectDAO.checkAccess(user, project); - - final TestReport latestReport = testReportRepository.findFirstByProject_IdOrderByIdDesc(projectId); - if (latestReport != null) { - loadLazyRelations(latestReport); - return latestReport; - } else { - return null; - } - } - - public TestReport update(User user, Long projectId, Long reportId, TestReport report) { - final Project project = projectRepository.findById(projectId).orElse(null); - final TestReport reportInDb = testReportRepository.findById(reportId).orElse(null); - checkAccess(user, project, reportInDb); - - reportInDb.setStatus(report.getStatus()); - reportInDb.setTestResults(report.getTestResults()); - reportInDb.getTestResults().forEach((testResult) -> { - testResult.setTestReport(reportInDb); - testResult.setProject(project); - }); - - return testReportRepository.save(reportInDb); - } - - public void delete(User user, Long projectId, Long testReportId) { - final Project project = projectRepository.findById(projectId).orElse(null); - final TestReport testReport = testReportRepository.findById(testReportId).orElse(null); - checkAccess(user, project, testReport); - - if (List.of(Status.IN_PROGRESS, Status.PENDING).contains(testReport.getStatus())) { - throw new IllegalArgumentException("Cannot delete report. Please abort the process first."); - } - - // delete screenshots - testReport.getTestResults().forEach(testResult -> { - if (testResult instanceof TestCaseResult) { - if (((TestCaseResult) testResult).getBeforeScreenshot() != null) { - final var filename = ((TestCaseResult) testResult).getBeforeScreenshot().getFilename(); - this.deleteScreenshot(user, projectId, testReportId, filename); - } - ((TestCaseResult) testResult).getOutputs().forEach(testExecutionResult -> { - if (testExecutionResult.getTestScreenshot() != null) { - final var filename = testExecutionResult.getTestScreenshot().getFilename(); - this.deleteScreenshot(user, projectId, testReportId, filename); - } - }); - } - }); - - testReportRepository.delete(testReport); - } - - public void delete(User user, Long projectId, List testReportIds) { - for (Long id : testReportIds) { - delete(user, projectId, id); - } - } - - public File getScreenshot(User user, Long projectId, Long testReportId, String screenshotName) { - final Project project = projectRepository.findById(projectId).orElse(null); - final TestReport testReport = testReportRepository.findById(testReportId).orElse(null); - checkAccess(user, project, testReport); - - final var filePath = filesRootDir + "/test_screenshots/" + project.getId() + "/" + screenshotName + ".png"; - final var screenshot = Paths.get(filePath).toFile(); - if (!screenshot.exists()) { - throw new NotFoundException("The requested screenshot does not exists."); - } - - return screenshot; - } - - public byte[] getScreenshotsAsZip(User user, Long projectId, Long testReportId, Long resultId) throws IOException { - final Project project = projectRepository.findById(projectId).orElse(null); - final TestReport testReport = testReportRepository.findById(testReportId).orElse(null); - checkAccess(user, project, testReport); - - final var result = testResultRepository.findById(resultId); - if (result.isEmpty()) { - throw new NotFoundException("The requested test result does not exist."); - } - - final var testResult = result.get(); - if (testResult instanceof TestSuiteResult) { - throw new IllegalArgumentException("The requested test result is of type TestCaseResult."); - } - - try ( - final var bos = new ByteArrayOutputStream(); - final var zos = new ZipOutputStream(bos) - ) { - final var testCaseResult = (TestCaseResult) testResult; - - final var beforeScreenshot = testCaseResult.getBeforeScreenshot(); - if (beforeScreenshot != null) { - var filename = beforeScreenshot.getFilename(); - var beforeScreenshotFile = this.getScreenshot(user, projectId, testReportId, filename); - writeToZipFile(beforeScreenshotFile, "000__screenshot_after_pre_symbols.png", zos); - } - - final var outputs = testCaseResult.getOutputs(); - for (int i = 0; i < outputs.size(); i++) { - var output = outputs.get(i); - if (output.getTestScreenshot() != null) { - var filename = output.getTestScreenshot().getFilename(); - var screenshotFile = this.getScreenshot(user, projectId, testReportId, filename); - writeToZipFile(screenshotFile, getScreenshotFilename(i, outputs.get(i)), zos); - } - } - - return bos.toByteArray(); - } - } - - public void deleteScreenshot(User user, Long projectId, Long testReportId, String screenshotName) { - final Project project = projectRepository.findById(projectId).orElse(null); - final TestReport testReport = testReportRepository.findById(testReportId).orElse(null); - checkAccess(user, project, testReport); - - final var filePath = filesRootDir + "/test_screenshots/" + project.getId() + "/" + screenshotName + ".png"; - final var screenshot = Paths.get(filePath).toFile(); - FileUtils.deleteQuietly(screenshot); - } - - public void deleteScreenshotDirectory(User user, Long projectId) { - final Project project = projectRepository.findById(projectId).orElse(null); - this.projectDAO.checkAccess(user, project); - - final var dirPath = filesRootDir + "/test_screenshots/" + project.getId(); - final var directory = Paths.get(dirPath).toFile(); - FileUtils.deleteQuietly(directory); - } - - public TestReport updateStatus(Long reportId, TestReport.Status status) { - final var report = testReportRepository.findById(reportId) - .orElseThrow(() -> new NotFoundException("report not found.")); - - report.setStatus(status); - - final var updatedReport = testReportRepository.save(report); - loadLazyRelations(updatedReport); - - return updatedReport; - } - - public TestReport getByID(Long reportId) { - final var report = testReportRepository.findById(reportId) - .orElseThrow(() -> new NotFoundException("report not found.")); - - loadLazyRelations(report); - - return report; - } - - public void checkAccess(User user, Project project, TestReport report) { - projectDAO.checkAccess(user, project); - - if (report == null) { - throw new NotFoundException("The test report could not be found."); - } - - if (!report.getProject().getId().equals(project.getId())) { - throw new UnauthorizedException("You are not allowed to access the test report."); - } - } - - private void writeToZipFile(File file, String targetPath, ZipOutputStream zos) throws IOException { - try (final var fis = new FileInputStream(file)) { - var zipEntry = new ZipEntry(targetPath); - zos.putNextEntry(zipEntry); - - byte[] bytes = new byte[1024]; - int length; - while ((length = fis.read(bytes)) >= 0) { - zos.write(bytes, 0, length); - } - - zos.closeEntry(); - } - } - - private String getScreenshotFilename(int i, TestExecutionResult testExecutionResult) { - return String.format("%03d", i + 1) - + "__" - + testExecutionResult.getSymbol().getName().replaceAll("\\s", "_") - + "__" - + testExecutionResult.getOutput().replaceAll("\\s", "_") - + ".png"; - } - - private void loadLazyRelations(TestReport testReport) { - Hibernate.initialize(testReport.getProject()); - Hibernate.initialize(testReport.getTestResults()); - Hibernate.initialize(testReport.getEnvironment()); - ProjectEnvironmentDAO.loadLazyRelations(testReport.getEnvironment()); - testReport.getTestResults().forEach(testResultDAO::loadLazyRelations); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/dao/TestResultDAO.java b/backend/src/main/java/de/learnlib/alex/testing/dao/TestResultDAO.java deleted file mode 100644 index 0643c00be..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/dao/TestResultDAO.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.dao; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.testing.entities.TestCaseResult; -import de.learnlib.alex.testing.entities.TestReport; -import de.learnlib.alex.testing.entities.TestResult; -import de.learnlib.alex.testing.repositories.TestReportRepository; -import org.apache.shiro.authz.UnauthorizedException; -import org.hibernate.Hibernate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(rollbackFor = Exception.class) -public class TestResultDAO { - - private final ProjectRepository projectRepository; - private final TestReportDAO testReportDAO; - private final TestReportRepository testReportRepository; - - @Autowired - public TestResultDAO( - ProjectRepository projectRepository, - @Lazy TestReportDAO testReportDAO, - TestReportRepository testReportRepository - ) { - this.projectRepository = projectRepository; - this.testReportDAO = testReportDAO; - this.testReportRepository = testReportRepository; - } - - public TestResult getByID(User user, Long projectId, Long reportId, Long testResultId) { - final var project = projectRepository.getOne(projectId); - final var report = testReportRepository.getOne(reportId); - final var result = report.getTestResults().stream() - .filter(r -> r.getId().equals(testResultId)) - .findFirst() - .orElse(null); - - checkAccess(user, project, report, result); - loadLazyRelations(result); - - return result; - } - - public void loadLazyRelations(TestResult testResult) { - if (testResult instanceof TestCaseResult) { - Hibernate.initialize(((TestCaseResult) testResult).getOutputs()); - } - } - - public void checkAccess(User user, Project project, TestReport testReport, TestResult testResult) { - testReportDAO.checkAccess(user, project, testReport); - - if (testResult == null) { - throw new NotFoundException("The test result could not be found."); - } - - if (!testResult.getTestReport().getId().equals(testReport.getId())) { - throw new UnauthorizedException("You are not allowed to access the test result"); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/entities/Test.java b/backend/src/main/java/de/learnlib/alex/testing/entities/Test.java deleted file mode 100644 index 35a50b692..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/entities/Test.java +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import de.learnlib.alex.data.entities.Project; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import javax.persistence.CascadeType; -import javax.persistence.DiscriminatorColumn; -import javax.persistence.DiscriminatorType; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Inheritance; -import javax.persistence.InheritanceType; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.OrderBy; -import javax.persistence.Transient; -import javax.validation.constraints.NotBlank; - -/** - * The entity for a test. - */ -@Entity -@Inheritance(strategy = InheritanceType.SINGLE_TABLE) -@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING) -@DiscriminatorValue("SUPER") -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") -@JsonSubTypes({ - @JsonSubTypes.Type(name = "case", value = TestCase.class), - @JsonSubTypes.Type(name = "suite", value = TestSuite.class), -}) -public class Test implements Serializable { - - private static final long serialVersionUID = 806158197227217171L; - - /** The representation of a test. */ - public static class TestRepresentation { - - /** The id of the test. */ - private Long id; - - /** The id of the parent of the test. */ - private Long parent; - - /** The name of the test. */ - private String name; - - /** The type of the test. */ - private String type; - - /** Constructor. */ - public TestRepresentation() { - } - - /** - * Constructor. - * - * @param test - * The test to represent. - */ - public TestRepresentation(Test test) { - this.id = test.id; - this.name = test.getName(); - this.type = test instanceof TestSuite ? "suite" : "case"; - this.parent = test.getParent().getId(); - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public Long getParent() { - return parent; - } - - public void setParent(Long parent) { - this.parent = parent; - } - } - - /** The id of the Test Case in the Project. */ - protected Long id; - - /** The Project the Test Case belongs to. */ - private Project project; - - /** The parent test suite. */ - private Test parent; - - /** The name of the Test Case. */ - @NotBlank - protected String name; - - /** The results where the test appears. */ - @OrderBy - private List testResults; - - /** Constructor. */ - public Test() { - this.testResults = new ArrayList<>(); - } - - /** - * Constructor. - * - * @param id - * The id of the test. - */ - public Test(Long id) { - this(); - this.id = id; - } - - @ManyToOne(fetch = FetchType.EAGER, optional = false) - @JoinColumn(name = "projectId") - @JsonIgnore - public Project getProject() { - return project; - } - - @JsonIgnore - public void setProject(Project project) { - this.project = project; - } - - @Transient - @JsonProperty("project") - public Long getProjectId() { - return project.getId(); - } - - @JsonProperty("project") - public void setProjectId(Long projectId) { - this.project = new Project(projectId); - } - - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "parentId") - @JsonIgnore - public Test getParent() { - return parent; - } - - @JsonIgnore - public void setParent(Test parent) { - this.parent = parent; - } - - @Transient - @JsonProperty("parent") - public Long getParentId() { - return parent == null ? null : parent.getId(); - } - - /** - * Set the parent test suite by an id. - * - * @param parentId - * The id of the parent. - */ - @JsonProperty("parent") - public void setParentId(Long parentId) { - if (parentId != null) { - this.parent = new Test(); - this.parent.setId(parentId); - } - } - - /** - * Get the ID of the Test Case (within the project). - * - * @return The ID. - */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @JsonProperty - public Long getId() { - return this.id; - } - - /** - * Set the ID of this Test Case (within the project). - * - * @param id - * The new ID. - */ - @JsonProperty - public void setId(Long id) { - this.id = id; - } - - /** - * Get the name of the Test Case. - * - * @return The name. - */ - @NotBlank - @JsonProperty - public String getName() { - return name; - } - - @JsonProperty - public void setName(String name) { - this.name = name; - } - - @OneToMany( - mappedBy = "test", - cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE} - ) - @JsonIgnore - public List getTestResults() { - return testResults; - } - - @JsonIgnore - public void setTestResults(List testResults) { - this.testResults = testResults; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/entities/TestCase.java b/backend/src/main/java/de/learnlib/alex/testing/entities/TestCase.java deleted file mode 100644 index b504ae525..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/entities/TestCase.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonTypeName; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.Constants; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.List; -import javax.persistence.CascadeType; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.OrderBy; -import javax.persistence.OrderColumn; -import javax.persistence.Transient; - -/** Test case. */ -@Entity -@DiscriminatorValue("case") -@JsonTypeName("case") -public class TestCase extends Test { - - private static final long serialVersionUID = 5961810799472877062L; - - /** The status of the test. */ - public enum Status { - - /** If it does not contain any steps. */ - EMPTY, - - /** If if contains at least one unimplemented symbol. */ - WORK_IN_PROGRESS, - - /** If not empty and there are no unimplemented symbols. */ - DONE - } - - /** - * Steps that are executed before the actual test. All steps have to pass in order for the test steps to be - * executed. - */ - @OrderColumn(name = "pre") - private List preSteps; - - /** The steps the test case is composed of. */ - @OrderColumn(name = "intermediate") - private List steps; - - /** - * Steps that are executed after the test. The steps are also executed if the test fails. The result of the post - * steps is ignored. - */ - @OrderColumn(name = "post") - private List postSteps; - - private boolean generated; - - /** The date when the symbol was updated the last time. */ - @JsonIgnore - private ZonedDateTime updatedOn; - - /** The last user who modified the symbol. */ - private User lastUpdatedBy; - - /** Constructor. */ - public TestCase() { - super(); - this.steps = new ArrayList<>(); - this.preSteps = new ArrayList<>(); - this.postSteps = new ArrayList<>(); - this.generated = false; - this.updatedOn = ZonedDateTime.now(); - this.lastUpdatedBy = null; - } - - @OneToMany( - orphanRemoval = true, - cascade = {CascadeType.ALL} - ) - @JoinTable( - name = "testCase_steps", - joinColumns = {@JoinColumn(name = "testCaseId", referencedColumnName = "id")}, - inverseJoinColumns = {@JoinColumn(name = "testCaseStepId", referencedColumnName = "id")} - ) - @OrderBy("number ASC") - public List getSteps() { - return steps; - } - - public void setSteps(List steps) { - this.steps = steps; - } - - @OneToMany( - orphanRemoval = true, - cascade = {CascadeType.ALL} - ) - @JoinTable( - name = "testCase_preSteps", - joinColumns = {@JoinColumn(name = "testCaseId", referencedColumnName = "id")}, - inverseJoinColumns = {@JoinColumn(name = "testCaseStepId", referencedColumnName = "id")} - ) - @OrderBy("number ASC") - public List getPreSteps() { - return preSteps; - } - - public void setPreSteps(List preSteps) { - this.preSteps = preSteps; - } - - @OneToMany( - orphanRemoval = true, - cascade = {CascadeType.ALL} - ) - @JoinTable( - name = "testCase_postSteps", - joinColumns = {@JoinColumn(name = "testCaseId", referencedColumnName = "id")}, - inverseJoinColumns = {@JoinColumn(name = "testCaseStepId", referencedColumnName = "id")} - ) - @OrderBy("number ASC") - public List getPostSteps() { - return postSteps; - } - - public void setPostSteps(List postSteps) { - this.postSteps = postSteps; - } - - @Transient - @JsonProperty("status") - public Status getStatus() { - if (this.steps.isEmpty()) { - return Status.EMPTY; - } else { - for (TestCaseStep step : steps) { - if (step.getPSymbol().getSymbol().getSteps().isEmpty()) { - return Status.WORK_IN_PROGRESS; - } - } - return Status.DONE; - } - } - - @JsonProperty("status") - public void setStatus(Status status) { - } - - public boolean isGenerated() { - return generated; - } - - public void setGenerated(boolean generated) { - this.generated = generated; - } - - public ZonedDateTime getUpdatedOn() { - return updatedOn; - } - - public void setUpdatedOn(ZonedDateTime updatedOn) { - this.updatedOn = updatedOn; - } - - @Transient - @JsonProperty("updatedOn") - public String getUpdatedOnString() { - return updatedOn.format(Constants.DATE_TIME_FORMATTER); - } - - @JsonProperty("updatedOn") - public void setUpdatedOnString(String updatedOnString) { - this.updatedOn = updatedOnString == null ? ZonedDateTime.now() : ZonedDateTime.parse(updatedOnString); - } - - @ManyToOne - @JoinColumn(name = "lastUpdatedById") - @JsonProperty("lastUpdatedBy") - public User getLastUpdatedBy() { - return this.lastUpdatedBy; - } - - @JsonIgnore - public void setLastUpdatedBy(User user) { - this.lastUpdatedBy = user; - } - - public boolean behavesLike(TestCase testCase) { - return areSameSteps(preSteps, testCase.preSteps) - && areSameSteps(postSteps, testCase.postSteps) - && areSameSteps(steps, testCase.steps); - } - - private boolean areSameSteps(List stepsA, List stepsB) { - if (stepsA.size() != stepsB.size()) { - return false; - } - - for (int i = 0; i < stepsA.size(); i++) { - if (!stepsA.get(i).behavesLike(stepsB.get(i))) { - return false; - } - } - - return true; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/entities/TestCaseResult.java b/backend/src/main/java/de/learnlib/alex/testing/entities/TestCaseResult.java deleted file mode 100644 index fcd716aec..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/entities/TestCaseResult.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonTypeName; -import java.util.ArrayList; -import java.util.List; -import javax.persistence.CascadeType; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.JoinColumn; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; -import javax.persistence.OrderBy; -import javax.persistence.Transient; - -/** - * The result of the execution of a test case. - */ -@Entity -@DiscriminatorValue("case") -@JsonTypeName("case") -public class TestCaseResult extends TestResult { - - private static final long serialVersionUID = -5995216881702329004L; - - /** The outputs of the system. */ - @OneToMany( - mappedBy = "result", - cascade = {CascadeType.ALL} - ) - @OrderBy - private List outputs; - - private Long failedStep; - - @OneToOne( - cascade = {CascadeType.ALL} - ) - @JoinColumn(name = "beforeTestScreenshotId") - private TestScreenshot beforeScreenshot; - - /** - * Constructor. - */ - public TestCaseResult() { - this.outputs = new ArrayList<>(); - this.failedStep = -1L; - } - - /** - * Constructor. - * - * @param testCase - * The test case that has been executed. - * @param outputs - * The recorded outputs. - * @param failedStep - * If the test passed. - * @param time - * The time it took to execute the test in ms. - */ - public TestCaseResult(TestCase testCase, List outputs, long failedStep, long time) { - super(testCase); - this.outputs = outputs; - this.time = time; - this.failedStep = failedStep; - - this.outputs.forEach(out -> { - out.setResult(this); - }); - } - - public List getOutputs() { - return outputs; - } - - public void setOutputs(List outputs) { - this.outputs = outputs; - } - - public Long getFailedStep() { - return failedStep; - } - - public void setFailedStep(Long failedStep) { - this.failedStep = failedStep; - } - - @Transient - @JsonProperty("passed") - public boolean isPassed() { - return this.failedStep.equals(-1L); - } - - @JsonIgnore - @JsonProperty("passed") - public void setPassed(boolean passed) { - } - - @Transient - @JsonProperty("failureMessage") - public String getFailureMessage() { - final List parts = new ArrayList<>(); - outputs.stream().filter(out -> !out.isSuccess()).forEach(out -> - parts.add(out.getSymbol().getName() + ": " + out.getMessage()) - ); - return parts.isEmpty() ? "" : String.join(", ", parts); - } - - @JsonIgnore - @JsonProperty("failureMessage") - public void setFailureMessage(String failureMessage) { - } - - public TestScreenshot getBeforeScreenshot() { - return beforeScreenshot; - } - - public void setBeforeScreenshot(TestScreenshot beforeScreenshot) { - this.beforeScreenshot = beforeScreenshot; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/entities/TestCaseStep.java b/backend/src/main/java/de/learnlib/alex/testing/entities/TestCaseStep.java deleted file mode 100644 index 854277dd4..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/entities/TestCaseStep.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import java.io.Serializable; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToOne; -import javax.persistence.OneToOne; -import javax.persistence.Transient; -import javax.validation.constraints.NotNull; - -/** The step of a test case. */ -@Entity -public class TestCaseStep implements Serializable { - - private static final long serialVersionUID = -8377670318070009082L; - - /** The database id. */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - /** The text case. */ - @ManyToOne(fetch = FetchType.EAGER, optional = false) - @JoinTable( - name = "testCase_testCaseStep", - joinColumns = {@JoinColumn(name = "testCaseStepId", referencedColumnName = "id")}, - inverseJoinColumns = {@JoinColumn(name = "testCaseId", referencedColumnName = "id")} - ) - @JsonIgnore - private TestCase testCase; - - /** The order number in the test. */ - @JsonIgnore - private int number; - - /** If disabled, the step is not executed. */ - private boolean disabled; - - /** The symbol to execute. */ - @OneToOne( - fetch = FetchType.EAGER, - cascade = CascadeType.ALL - ) - private ParameterizedSymbol pSymbol; - - /** The expected result of the step in a natural language. */ - @Column(columnDefinition = "TEXT") - private String expectedResult; - - @NotNull - private boolean expectedOutputSuccess; - - @NotNull - private String expectedOutputMessage; - - /** Constructor. */ - public TestCaseStep() { - this.expectedResult = ""; - this.expectedOutputSuccess = true; - this.expectedOutputMessage = ""; - this.disabled = false; - } - - @Transient - @JsonIgnore - public String getComputedOutput() { - return new ExecuteResult(expectedOutputSuccess, expectedOutputMessage.equals("") ? null : expectedOutputMessage).getOutput(); - } - - /** - * Executes the step. - * - * @param connectors - * The connector manager. - * @return The result of the step. - */ - public ExecuteResult execute(ConnectorManager connectors) { - return pSymbol.execute(connectors); - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public TestCase getTestCase() { - return testCase; - } - - public void setTestCase(TestCase testCase) { - this.testCase = testCase; - } - - public int getNumber() { - return number; - } - - public void setNumber(int number) { - this.number = number; - } - - @JsonProperty("pSymbol") - public ParameterizedSymbol getPSymbol() { - return pSymbol; - } - - @JsonProperty("pSymbol") - public void setPSymbol(ParameterizedSymbol pSymbol) { - this.pSymbol = pSymbol; - } - - public String getExpectedResult() { - return expectedResult; - } - - public void setExpectedResult(String expectedResult) { - this.expectedResult = expectedResult == null ? "" : expectedResult; - } - - public boolean isExpectedOutputSuccess() { - return expectedOutputSuccess; - } - - public void setExpectedOutputSuccess(boolean expectedOutputSuccess) { - this.expectedOutputSuccess = expectedOutputSuccess; - } - - public String getExpectedOutputMessage() { - return expectedOutputMessage; - } - - public void setExpectedOutputMessage(String expectedOutputMessage) { - this.expectedOutputMessage = expectedOutputMessage; - } - - public boolean isDisabled() { - return disabled; - } - - public void setDisabled(boolean disabled) { - this.disabled = disabled; - } - - public boolean behavesLike(TestCaseStep step) { - return getComputedOutput().equals(step.getComputedOutput()) - && pSymbol.getAliasOrComputedName().equals(step.getPSymbol().getAliasOrComputedName()); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/entities/TestExecutionConfig.java b/backend/src/main/java/de/learnlib/alex/testing/entities/TestExecutionConfig.java deleted file mode 100644 index 2bb0e7a9c..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/entities/TestExecutionConfig.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.entities; - -import com.fasterxml.jackson.annotation.JsonProperty; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.learning.entities.WebDriverConfig; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; -import javax.persistence.CascadeType; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.OneToOne; -import javax.persistence.OrderBy; -import javax.persistence.Transient; -import javax.validation.constraints.NotNull; - -/** - * The configuration class for running multiple tests in a batch. - */ -@Entity -public class TestExecutionConfig implements Serializable { - - private static final long serialVersionUID = -1523151999366958537L; - - /** The id of the config in the database. */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - /** The name of the config. */ - private String name; - - /** The ids of the tests to execute. */ - @ManyToMany - @OrderBy - private List tests; - - /** The configuration for the web driver. */ - @NotNull - @OneToOne(cascade = CascadeType.ALL) - private WebDriverConfig driverConfig; - - /** The id of the URL to use for testing. */ - @NotNull - @OneToOne - private ProjectEnvironment environment; - - /** The project where the config is saved. */ - @ManyToOne - @JoinColumn(name = "projectId") - private Project project; - - private boolean isDefault; - - /** The user defined description of the config. */ - private String description; - - /** Constructor. */ - public TestExecutionConfig() { - this(new ArrayList<>(), new WebDriverConfig()); - } - - /** - * Constructor. - * - * @param testIds - * The ids of the tests. - * @param driverConfig - * The configuration for the web driver. - */ - public TestExecutionConfig(List testIds, WebDriverConfig driverConfig) { - this.setTestIds(testIds); - this.driverConfig = driverConfig; - this.isDefault = false; - this.description = ""; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name == null || name.trim().equals("") ? "" : name; - } - - public List getTests() { - return tests; - } - - public void setTests(List tests) { - this.tests = tests; - } - - @Transient - @JsonProperty("tests") - public List getTestIds() { - return tests.stream().map(Test::getId).collect(Collectors.toList()); - } - - @JsonProperty("tests") - public void setTestIds(List testIds) { - this.tests = testIds.stream() - .map(Test::new) - .collect(Collectors.toList()); - } - - public ProjectEnvironment getEnvironment() { - return environment; - } - - public void setEnvironment(ProjectEnvironment environment) { - this.environment = environment; - } - - @Transient - @JsonProperty("environmentId") - public Long getEnvironmentId() { - return environment.getId(); - } - - @JsonProperty("environmentId") - public void setEnvironmentId(Long environmentId) { - this.environment = new ProjectEnvironment(); - this.environment.setId(environmentId); - } - - public WebDriverConfig getDriverConfig() { - return driverConfig; - } - - public void setDriverConfig(WebDriverConfig driverConfig) { - this.driverConfig = driverConfig; - } - - public Project getProject() { - return project; - } - - public void setProject(Project project) { - this.project = project; - } - - @Transient - @JsonProperty("project") - public Long getProjectId() { - return project == null ? null : project.getId(); - } - - @JsonProperty("project") - public void setProjectId(Long projectId) { - this.project = new Project(projectId); - } - - public boolean isDefault() { - return isDefault; - } - - public void setDefault(boolean aDefault) { - isDefault = aDefault; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof TestExecutionConfig)) { - return false; - } - TestExecutionConfig that = (TestExecutionConfig) o; - return Objects.equals(getId(), that.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(getId()); - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/entities/TestExecutionResult.java b/backend/src/main/java/de/learnlib/alex/testing/entities/TestExecutionResult.java deleted file mode 100644 index 7190190a1..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/entities/TestExecutionResult.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Symbol; -import java.io.Serializable; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; - -/** - * Wrapper for {@link de.learnlib.alex.data.entities.ExecuteResult} that allows persistence for tests. - */ -@Entity -public class TestExecutionResult extends ExecuteResult implements Serializable { - - private static final long serialVersionUID = -3528131025646284916L; - - /** - * The referenced test result. - */ - @ManyToOne(fetch = FetchType.EAGER, optional = false) - @JoinColumn(name = "testResultId") - @JsonIgnore - private TestCaseResult result; - - /** - * The symbols that produced the result. - */ - @ManyToOne(fetch = FetchType.EAGER, optional = false) - @JoinColumn(name = "symbolId") - private Symbol symbol; - - public TestExecutionResult() { - super(); - } - - public TestExecutionResult(ExecuteResult result) { - super(result.isSuccess(), result.getMessage(), result.getTrace(), result.getTime(), result.getTestScreenshot()); - } - - public TestCaseResult getResult() { - return result; - } - - public void setResult(TestCaseResult result) { - this.result = result; - } - - public Symbol getSymbol() { - return symbol; - } - - public void setSymbol(Symbol symbol) { - this.symbol = symbol; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/entities/TestOptions.java b/backend/src/main/java/de/learnlib/alex/testing/entities/TestOptions.java deleted file mode 100644 index 7ce85c5aa..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/entities/TestOptions.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.entities; - -import de.learnlib.alex.webhooks.entities.Webhook; - -/** Options to pass to the test run. */ -public class TestOptions { - - private Webhook webhook; - - public Webhook getWebhook() { - return webhook; - } - - public void setWebhook(Webhook webhook) { - this.webhook = webhook; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/entities/TestProcessQueueItem.java b/backend/src/main/java/de/learnlib/alex/testing/entities/TestProcessQueueItem.java deleted file mode 100644 index 179e8b2ee..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/entities/TestProcessQueueItem.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.entities; - -public class TestProcessQueueItem { - public Long userId; - public Long projectId; - public Long reportId; - public TestExecutionConfig config; - - public TestProcessQueueItem(Long userId, Long projectId, Long reportId, TestExecutionConfig config) { - this.userId = userId; - this.projectId = projectId; - this.reportId = reportId; - this.config = config; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/entities/TestQueueItem.java b/backend/src/main/java/de/learnlib/alex/testing/entities/TestQueueItem.java deleted file mode 100644 index 86361eda4..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/entities/TestQueueItem.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.entities; - -import java.util.HashMap; -import java.util.Map; - -public class TestQueueItem { - - private TestReport report; - private TestExecutionConfig config; - private Map results; - - public TestQueueItem() { - this.results = new HashMap<>(); - } - - public TestQueueItem(TestReport report, TestExecutionConfig config) { - this(); - this.report = report; - this.config = config; - } - - public TestReport getReport() { - return report; - } - - public void setReport(TestReport report) { - this.report = report; - } - - public TestExecutionConfig getConfig() { - return config; - } - - public void setConfig(TestExecutionConfig config) { - this.config = config; - } - - public Map getResults() { - return results; - } - - public void setResults(Map results) { - this.results = results; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/entities/TestReport.java b/backend/src/main/java/de/learnlib/alex/testing/entities/TestReport.java deleted file mode 100644 index 390457e01..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/entities/TestReport.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.ProjectEnvironment; -import java.io.Serializable; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.List; -import javax.persistence.CascadeType; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; -import javax.persistence.OrderBy; -import javax.persistence.Transient; - -/** The test report. */ -@Entity -public class TestReport implements Serializable { - - private static final long serialVersionUID = 1046158779314008741L; - - /** The date formatter for the report. */ - private static final DateTimeFormatter DATE_TIME_FORMATTER = - DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSxxx"); - - - public enum Status { - PENDING, - IN_PROGRESS, - FINISHED, - ABORTED - } - - /** The id in the database. */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - /** The project the report belongs to. */ - @ManyToOne(fetch = FetchType.EAGER, optional = false) - @JsonIgnore - private Project project; - - /** When the test started. */ - @JsonIgnore - private ZonedDateTime startDate; - - /** The results of the tests that have been executed in the test run. */ - @OneToMany( - mappedBy = "testReport", - cascade = {CascadeType.ALL} - ) - @OrderBy - private List testResults; - - /** The environment that the test was executed in. */ - @OneToOne(fetch = FetchType.EAGER) - private ProjectEnvironment environment; - - private Status status; - - /** The user defined description of the corresponding execution config. */ - private String description; - - /** The user who started the test. */ - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "executedById") - private User executedBy; - - /** Constructor. */ - public TestReport() { - this.testResults = new ArrayList<>(); - this.startDate = ZonedDateTime.now(); - this.status = Status.PENDING; - this.description = ""; - } - - public ZonedDateTime getStartDate() { - return startDate; - } - - public void setStartDate(ZonedDateTime startDate) { - this.startDate = startDate; - } - - @JsonProperty("startDate") - public String getStartDateAsString() { - return startDate.format(DATE_TIME_FORMATTER); - } - - @JsonProperty("startDate") - public void setStartDateByString(String dateAsString) { - this.startDate = ZonedDateTime.parse(dateAsString); - } - - public Project getProject() { - return project; - } - - public void setProject(Project project) { - this.project = project; - } - - @JsonProperty("project") - public Long getProjectId() { - return this.project == null ? 0 : this.project.getId(); - } - - @JsonProperty("project") - public void setProjectId(Long projectId) { - this.project = new Project(projectId); - } - - public ProjectEnvironment getEnvironment() { - return environment; - } - - public void setEnvironment(ProjectEnvironment environment) { - this.environment = environment; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public List getTestResults() { - return testResults; - } - - public void setTestResults(List testResults) { - this.testResults = testResults; - } - - @JsonProperty("executedBy") - public User getExecutedBy() { - return executedBy; - } - - @JsonIgnore - public void setExecutedBy(User executedBy) { - this.executedBy = executedBy; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - /** - * Evaluate if the test run passed. - * - * @return If the test run passed. - */ - @Transient - public boolean isPassed() { - return this.status.equals(Status.FINISHED) && this.testResults.stream() - .map(TestResult::isPassed) - .reduce(true, (a, b) -> a && b); - } - - /** - * Calculate the time it took to execute the tests. - * - * @return The time in ms. - */ - @Transient - public Long getTime() { - return this.testResults.stream() - .filter(r -> r instanceof TestCaseResult) - .map(TestResult::getTime) - .reduce(0L, Long::sum); - } - - /** - * Count the number of test cases that have been executed. - * - * @return The number of tests. - */ - @Transient - public Long getNumTests() { - return this.testResults.stream() - .filter(r -> r instanceof TestCaseResult) - .count(); - } - - /** - * Count the number of test cases that failed. - * - * @return The number of tests that failed. - */ - @Transient - public Long getNumTestsFailed() { - return this.testResults.stream() - .filter(r -> r instanceof TestCaseResult) - .filter(r -> !r.isPassed()) - .count(); - } - - /** - * Count the number of test cases that passed. - * - * @return The number of tests that passed. - */ - @Transient - public Long getNumTestsPassed() { - return this.testResults.stream() - .filter(r -> r instanceof TestCaseResult) - .filter(TestResult::isPassed) - .count(); - } - - public Status getStatus() { - return status; - } - - public void setStatus(Status status) { - this.status = status; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/entities/TestResult.java b/backend/src/main/java/de/learnlib/alex/testing/entities/TestResult.java deleted file mode 100644 index 6ecf40e6b..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/entities/TestResult.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import de.learnlib.alex.data.entities.Project; -import java.io.Serializable; -import java.util.Optional; -import javax.persistence.DiscriminatorColumn; -import javax.persistence.DiscriminatorType; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Inheritance; -import javax.persistence.InheritanceType; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.Transient; - -/** - * The result of a test execution. - */ -@Entity -@Inheritance(strategy = InheritanceType.SINGLE_TABLE) -@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING) -@DiscriminatorValue("SUPER") -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") -@JsonSubTypes({ - @JsonSubTypes.Type(name = "case", value = TestCaseResult.class), - @JsonSubTypes.Type(name = "suite", value = TestSuiteResult.class), -}) -public abstract class TestResult implements Serializable { - - private static final long serialVersionUID = -4509801862717378522L; - - /** The ID of the test result in the database. */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - /** The test that has been executed. */ - @ManyToOne - @JoinColumn(name = "testId") - @JsonIgnore - private Test test; - - /** The test that has been executed. */ - @ManyToOne - @JoinColumn(name = "testReportId") - @JsonIgnore - private TestReport testReport; - - /** The project the counter belongs to. */ - @ManyToOne(fetch = FetchType.EAGER, optional = false) - @JsonIgnore - private Project project; - - /** The time it took to execute the test in ms. */ - protected long time; - - /** - * Constructor. - */ - public TestResult() { - } - - /** - * Constructor. - * - * @param test - * The test that has been executed. - */ - public TestResult(Test test) { - this.test = test; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Test getTest() { - return test; - } - - public void setTest(Test test) { - this.test = test; - } - - @JsonProperty("test") - public Test.TestRepresentation getTestRepresentation() { - return new Test.TestRepresentation(test); - } - - /** - * The the associated test by its ID. - * - * @param testId - * The ID of the test. - */ - @JsonProperty("test") - public void setTestId(Long testId) { - this.test = new Test(); - this.test.setId(testId); - } - - public TestReport getTestReport() { - return testReport; - } - - public void setTestReport(TestReport testReport) { - this.testReport = testReport; - } - - public long getTime() { - return time; - } - - public void setTime(long time) { - this.time = time; - } - - public Project getProject() { - return project; - } - - public void setProject(Project project) { - this.project = project; - } - - @JsonProperty("project") - public Long getProjectId() { - return this.project == null ? 0 : this.project.getId(); - } - - @JsonProperty("project") - public void setProjectId(Long projectId) { - this.project = new Project(projectId); - } - - @JsonProperty("report") - public Long getReportId() { - return Optional.ofNullable(this.testReport) - .map(TestReport::getId) - .orElse(null); - } - - /** - * Checks if the executed test case or test suite passed. A suite passed if all test cases and child test suites - * passed, too. - * - * @return If the test passsed. - */ - @Transient - public abstract boolean isPassed(); - - @Transient - @JsonProperty("date") - public String getDate() { - return testReport == null ? null : testReport.getStartDateAsString(); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/entities/TestScreenshot.java b/backend/src/main/java/de/learnlib/alex/testing/entities/TestScreenshot.java deleted file mode 100644 index c75c2cedc..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/entities/TestScreenshot.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.entities; - -import java.io.Serializable; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.validation.constraints.NotEmpty; - -@Entity -public class TestScreenshot implements Serializable { - - private static final long serialVersionUID = -6608252802941079821L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private long id; - - @NotEmpty - private String filename; - - public TestScreenshot() { - } - - public String getFilename() { - return filename; - } - - public void setFilename(String filename) { - this.filename = filename; - } - - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/entities/TestStatus.java b/backend/src/main/java/de/learnlib/alex/testing/entities/TestStatus.java deleted file mode 100644 index 0bedc0a6c..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/entities/TestStatus.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.entities; - -import java.util.ArrayList; -import java.util.List; - -/** - * The class that contains the current status of a test process. - */ -public class TestStatus { - - private List testRunQueue; - - private TestQueueItem currentTestRun; - - /** The test(suite) that is currently being executed. */ - private Test currentTest; - - /** Constructor. */ - public TestStatus() { - testRunQueue = new ArrayList<>(); - } - - public TestQueueItem getCurrentTestRun() { - return currentTestRun; - } - - public void setCurrentTestRun(TestQueueItem currentTestRun) { - this.currentTestRun = currentTestRun; - } - - public List getTestRunQueue() { - return testRunQueue; - } - - public void setTestRunQueue(List testRunQueue) { - this.testRunQueue = testRunQueue; - } - - public boolean isActive() { - return !(testRunQueue.isEmpty() && currentTestRun == null && currentTest == null); - } - - public Test getCurrentTest() { - return currentTest; - } - - public void setCurrentTest(Test currentTest) { - this.currentTest = currentTest; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/entities/TestSuite.java b/backend/src/main/java/de/learnlib/alex/testing/entities/TestSuite.java deleted file mode 100644 index ab69cdee6..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/entities/TestSuite.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonTypeName; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; -import javax.persistence.CascadeType; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.OneToMany; -import javax.persistence.Transient; - -/** - * Test suite. - * Can contain other test suites or test cases. - */ -@Entity -@DiscriminatorValue("suite") -@JsonTypeName("suite") -public class TestSuite extends Test { - - private static final long serialVersionUID = 3997432889140612741L; - - /** The tests that belong to the test suite. */ - private List tests; - - /** The IDs of the tests that belong the the test suite. */ - private List testsAsIds; - - /** Constructor. */ - public TestSuite() { - this.tests = new ArrayList<>(); - this.testsAsIds = new ArrayList<>(); - } - - @OneToMany( - mappedBy = "parent", - cascade = {CascadeType.PERSIST, CascadeType.REMOVE} - ) - @JsonProperty("tests") - public List getTests() { - return tests; - } - - @Transient - @JsonIgnore - public List getTestsAsIds() { - if (testsAsIds == null || testsAsIds.isEmpty()) { - testsAsIds = new ArrayList<>(); - } - return testsAsIds; - } - - @JsonIgnore - public void setTests(List tests) { - if (tests == null) { - this.tests = new ArrayList<>(); - } else { - this.tests = tests; - this.testsAsIds = tests.stream().map(Test::getId).collect(Collectors.toList()); - } - } - - @Transient - @JsonProperty("testIds") - public void setTestsAsIds(List testsAsIds) { - this.testsAsIds = testsAsIds; - } - - @Transient - @JsonProperty("tests") - public void setTestsAsTests(List tests) { - this.tests = tests; - } - - @JsonIgnore - public void addTest(Test test) { - this.tests.add(test); - test.setParent(this); - } - - /** - * Check if the test suite is a descendant of another test suite. - * - * @param ancestor - * The ancestor in the test suite tree. - * @return True, if the test suite is a descendant. - */ - public boolean isDescendantOf(TestSuite ancestor) { - if (ancestor.getId().equals(id)) { - return false; - } - - final List testSuites = new ArrayList<>(); - ancestor.getTests().stream() - .filter(TestSuite.class::isInstance) - .forEach(ts -> testSuites.add((TestSuite) ts)); - - for (TestSuite testSuite : testSuites) { - boolean isDescendant = testSuite.getId().equals(id) || isDescendantOf(testSuite); - if (isDescendant) { - return true; - } - } - - return false; - } - - @Transient - @JsonIgnore - public List getTestSuites() { - return tests.stream().filter(t -> t instanceof TestSuite).map(t -> (TestSuite) t).collect(Collectors.toList()); - } - - @Transient - @JsonIgnore - public List getTestCases() { - return tests.stream().filter(t -> t instanceof TestCase).map(t -> (TestCase) t).collect(Collectors.toList()); - } - - public int indexOfTestCaseThatBehavesLike(TestCase testCase) { - for (int i = 0; i < this.tests.size(); i++) { - final Test test = this.tests.get(i); - if (test instanceof TestCase && ((TestCase) test).behavesLike(testCase)) { - return i; - } - } - return -1; - } -} - diff --git a/backend/src/main/java/de/learnlib/alex/testing/entities/TestSuiteResult.java b/backend/src/main/java/de/learnlib/alex/testing/entities/TestSuiteResult.java deleted file mode 100644 index f1b7355f8..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/entities/TestSuiteResult.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.entities; - -import com.fasterxml.jackson.annotation.JsonTypeName; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.Transient; - -/** - * The result of the execution of a test suite. - */ -@Entity -@DiscriminatorValue("suite") -@JsonTypeName("suite") -public class TestSuiteResult extends TestResult { - - private static final long serialVersionUID = 6838201007001578578L; - - /** How many test cases passed. */ - private long testCasesPassed; - - /** How many test cases failed. */ - private long testCasesFailed; - - /** - * Constructor. - */ - public TestSuiteResult() { - } - - /** - * Constructor. - * - * @param testSuite - * The test suite that has been executed. - * @param testCasesPassed - * The number of test cases that passed. - * @param testCasesFailed - * The number of test cases that failed. - */ - public TestSuiteResult(TestSuite testSuite, long testCasesPassed, long testCasesFailed) { - super(testSuite); - this.testCasesPassed = testCasesPassed; - this.testCasesFailed = testCasesFailed; - } - - /** - * Adds result from children test cases. - * - * @param result - * The test case in this suite. - */ - public void add(TestCaseResult result) { - testCasesPassed += result.isPassed() ? 1 : 0; - testCasesFailed += !result.isPassed() ? 1 : 0; - time += result.getTime(); - } - - /** - * Adds result from children test suites. - * - * @param result - * The test suite in this suite. - */ - public void add(TestSuiteResult result) { - testCasesPassed += result.getTestCasesPassed(); - testCasesFailed += result.getTestCasesFailed(); - time += result.getTime(); - } - - /** - * Calculate the number of test cases that run. - * - * @return The number of test cases. - */ - @Transient - public long getTestCasesRun() { - return testCasesPassed + testCasesFailed; - } - - public void setTestCasesRun(long num) { - } - - public long getTestCasesPassed() { - return testCasesPassed; - } - - public void setTestCasesPassed(long testCasesPassed) { - this.testCasesPassed = testCasesPassed; - } - - public long getTestCasesFailed() { - return testCasesFailed; - } - - public void setTestCasesFailed(long testCasesFailed) { - this.testCasesFailed = testCasesFailed; - } - - /** - * Check if the test suite passed. - * - * @return True if all test cases and nested test suites passed. - */ - @Transient - @Override - public boolean isPassed() { - return testCasesFailed == 0; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/entities/export/TestExecutionConfigExportableEntity.java b/backend/src/main/java/de/learnlib/alex/testing/entities/export/TestExecutionConfigExportableEntity.java deleted file mode 100644 index 9e692f58f..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/entities/export/TestExecutionConfigExportableEntity.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.entities.export; - -import com.fasterxml.jackson.databind.JsonNode; -import de.learnlib.alex.data.entities.export.ExportableEntity; - -public class TestExecutionConfigExportableEntity extends ExportableEntity { - - private JsonNode testConfigs; - - public TestExecutionConfigExportableEntity(String version, JsonNode testConfigs) { - super(version, "testConfigs"); - this.testConfigs = testConfigs; - } - - public JsonNode getTestConfigs() { - return testConfigs; - } - - public void setTestConfigs(JsonNode testConfigs) { - this.testConfigs = testConfigs; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/entities/export/TestsExportConfig.java b/backend/src/main/java/de/learnlib/alex/testing/entities/export/TestsExportConfig.java deleted file mode 100644 index 773adc7d3..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/entities/export/TestsExportConfig.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.entities.export; - -import java.util.ArrayList; -import java.util.List; - -public class TestsExportConfig { - - /** The ids of the tests to export. */ - private List testIds = new ArrayList<>(); - - public List getTestIds() { - return testIds; - } - - public void setTestIds(List testIds) { - this.testIds = testIds; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/entities/export/TestsExportableEntity.java b/backend/src/main/java/de/learnlib/alex/testing/entities/export/TestsExportableEntity.java deleted file mode 100644 index 68ea06c92..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/entities/export/TestsExportableEntity.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.entities.export; - -import com.fasterxml.jackson.databind.JsonNode; -import de.learnlib.alex.data.entities.export.ExportableEntity; - -public class TestsExportableEntity extends ExportableEntity { - - private JsonNode tests; - - public TestsExportableEntity(String version, JsonNode tests) { - super(version, "tests"); - this.tests = tests; - } - - public JsonNode getTests() { - return tests; - } - - public void setTests(JsonNode tests) { - this.tests = tests; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/events/TestEvent.java b/backend/src/main/java/de/learnlib/alex/testing/events/TestEvent.java deleted file mode 100644 index 6ca8a7bba..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/events/TestEvent.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.events; - -import de.learnlib.alex.testing.entities.Test; -import de.learnlib.alex.testing.entities.TestReport; -import de.learnlib.alex.webhooks.entities.Event; -import de.learnlib.alex.webhooks.entities.EventType; -import java.util.List; - -/** Events for tests. */ -public class TestEvent { - - /** Event for when a test is created. */ - public static class Created extends Event { - - /** - * Constructor. - * - * @param test - * The created test. - */ - public Created(Test test) { - super(test, EventType.TEST_CREATED); - } - } - - /** Event for when a test is updated. */ - public static class Updated extends Event { - - /** - * Constructor. - * - * @param test - * The updated test. - */ - public Updated(Test test) { - super(test, EventType.TEST_UPDATED); - } - } - - /** Event for when a test is deleted. */ - public static class Deleted extends Event { - - /** - * Constructor. - * - * @param id - * The id of the deleted test. - */ - public Deleted(Long id) { - super(id, EventType.TEST_DELETED); - } - } - - /** Event for when the test execution finished. */ - public static class ExecutionFinished extends Event { - - /** - * Constructor. - * - * @param report - * The report of the test execution. - */ - public ExecutionFinished(TestReport report) { - super(report, EventType.TEST_EXECUTION_FINISHED); - } - } - - /** Event for when the test execution started. */ - public static class ExecutionStarted extends Event { - - /** - * Constructor. - * - * @param data - * The data used to start the test execution. - */ - public ExecutionStarted(TestExecutionStartedEventData data) { - super(data, EventType.TEST_EXECUTION_STARTED); - } - } - - /** Event for when multiple tests are created at once. */ - public static class CreatedMany extends Event> { - - /** - * Constructor. - * - * @param tests - * The created tests. - */ - public CreatedMany(List tests) { - super(tests, EventType.TESTS_CREATED); - } - } - - /** Event for when multiple tests are deleted at once. */ - public static class DeletedMany extends Event> { - - /** - * Constructor. - * - * @param ids - * The ids of the deleted tests. - */ - public DeletedMany(List ids) { - super(ids, EventType.TESTS_DELETED); - } - } - - /** Event for when multiple tests are moved to an new test suite. */ - public static class MovedMany extends Event> { - - /** - * Constructor. - * - * @param tests - * The moved tests. - */ - public MovedMany(List tests) { - super(tests, EventType.TESTS_MOVED); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/events/TestExecutionStartedEventData.java b/backend/src/main/java/de/learnlib/alex/testing/events/TestExecutionStartedEventData.java deleted file mode 100644 index fb19f29d8..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/events/TestExecutionStartedEventData.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.events; - -import de.learnlib.alex.testing.entities.TestExecutionConfig; - -/** The data used for starting the test execution. */ -public class TestExecutionStartedEventData extends TestExecutionConfig { - - /** The id of the project. */ - private Long projectId; - - /** - * Constructor. - * - * @param projectId - * {@link #projectId}. - * @param config - * The configuration to use. - */ - public TestExecutionStartedEventData(Long projectId, TestExecutionConfig config) { - this.projectId = projectId; - this.setTestIds(config.getTestIds()); - this.setDriverConfig(config.getDriverConfig()); - } - - public Long getProjectId() { - return projectId; - } - - public void setProjectId(Long projectId) { - this.projectId = projectId; - } -} - - diff --git a/backend/src/main/java/de/learnlib/alex/testing/repositories/TestCaseStepRepository.java b/backend/src/main/java/de/learnlib/alex/testing/repositories/TestCaseStepRepository.java deleted file mode 100644 index bfc21ca55..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/repositories/TestCaseStepRepository.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.repositories; - -import de.learnlib.alex.testing.entities.TestCaseStep; -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** The repository for test case steps. */ -@Repository -public interface TestCaseStepRepository extends JpaRepository { - - /** - * Delete all those test steps of a test whose ids are not specified to stay. This should be used when updating a - * test case. - * - * @param testId - * The id of the test in the db. - * @param testCaseIds - * The ids of the test case steps in the db. - */ - void deleteAllByTestCase_IdAndIdNotIn(Long testId, List testCaseIds); - - /** - * Count the number of test steps that use a symbol. - * - * @param symbolId - * The ID of the symbol. - * @return The count. - */ - Long countAllBypSymbol_Symbol_Id(Long symbolId); - - List findAllBypSymbol_Symbol_Id(Long symbolId); -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/repositories/TestExecutionConfigRepository.java b/backend/src/main/java/de/learnlib/alex/testing/repositories/TestExecutionConfigRepository.java deleted file mode 100644 index 50e1d7da9..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/repositories/TestExecutionConfigRepository.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.repositories; - -import de.learnlib.alex.testing.entities.TestExecutionConfig; -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; - -/** Repository for test execution configs. */ -@Repository -public interface TestExecutionConfigRepository extends JpaRepository { - - /** - * Get all configurations by a project id. - * - * @param projectId - * The id of the project. - * @return The configurations. - */ - List findAllByProject_Id(Long projectId); - - void deleteAllByProject_Id(Long projectId); - - @Query(nativeQuery = true, value = "select * from PUBLIC.test_execution_config where project_id = ? and is_default = true limit 1") - TestExecutionConfig findByProject_IdAndIs_Default(Long projectId); - - @Query(value = "select tc " - + "from TestExecutionConfig tc join tc.tests t " - + "where tc.project.id = :projectId and t.id = :testId") - List findAllByProject_IdAndTest_Id(@Param("projectId") Long projectId, @Param("testId") Long testId); - - List findAllByProject_IdAndEnvironment_Id(Long projectId, Long environmentId); -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/repositories/TestExecutionResultRepository.java b/backend/src/main/java/de/learnlib/alex/testing/repositories/TestExecutionResultRepository.java deleted file mode 100644 index 5139b65e5..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/repositories/TestExecutionResultRepository.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.repositories; - -import de.learnlib.alex.testing.entities.TestExecutionResult; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** The repository for test results. */ -@Repository -public interface TestExecutionResultRepository extends JpaRepository { - - /** - * Count all results by used symbol ID. - * - * @param symbolId - * The ID of the symbol. - * @return The count. - */ - Long countAllBySymbol_Id(Long symbolId); -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/repositories/TestReportRepository.java b/backend/src/main/java/de/learnlib/alex/testing/repositories/TestReportRepository.java deleted file mode 100644 index 2a10ea9fd..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/repositories/TestReportRepository.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.repositories; - -import de.learnlib.alex.testing.entities.TestReport; -import java.util.List; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** The repository for test reports. */ -@Repository -public interface TestReportRepository extends JpaRepository { - - /** - * Get the latest test report in a project. - * - * @param projectId - * The id of the project. - * @return The latest test report. - */ - TestReport findFirstByProject_IdOrderByIdDesc(Long projectId); - - /** - * Get all test reports in a project. - * - * @param projectId - * The id of the project. - * @param pageable - * The pageable object. - * @return The test reports. - */ - Page findAllByProject_Id(Long projectId, Pageable pageable); - - List findAllByStatusIn(List statusList); - - /** - * Delete all test reports by project id. - * - * @param projectId - * The id of the project. - * @return The number of deleted test reports. - */ - Long deleteAllByProject_Id(Long projectId); - - void deleteAllByEnvironment_Id(Long envId); -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/repositories/TestRepository.java b/backend/src/main/java/de/learnlib/alex/testing/repositories/TestRepository.java deleted file mode 100644 index 60d3ef662..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/repositories/TestRepository.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.repositories; - -import de.learnlib.alex.testing.entities.Test; -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** Repository to persist tests. */ -@Repository -public interface TestRepository extends JpaRepository { - - /** - * Find a test by its name within its parent. - * - * @param parentId - * The id of the parent. - * @param name - * The name of the test. - * @return The test matching the name. - */ - Test findOneByParent_IdAndName(Long parentId, String name); - - /** - * Get the default test suite. - * - * @param projectId - * The id of the project. - * @return The default test suite. - */ - Test findFirstByProject_IdOrderByIdAsc(Long projectId); - - /** - * Get all tests of a project. - * - * @param projectId - * The id of the project. - * @return The tests in the project. - */ - List findAllByProject_Id(Long projectId); - - void deleteAllByProject_Id(Long projectId); - - List findAllByProject_IdAndIdIn(Long projectId, List testIds); -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/repositories/TestResultRepository.java b/backend/src/main/java/de/learnlib/alex/testing/repositories/TestResultRepository.java deleted file mode 100644 index b7573d8d4..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/repositories/TestResultRepository.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.repositories; - -import de.learnlib.alex.testing.entities.TestResult; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** - * Repository for test results. - */ -@Repository -public interface TestResultRepository extends JpaRepository { - - /** - * Get all test results of a test. - * - * @param testId - * The ID of the test. - * @param pageable - * The pageable object. - * @return The test results in descending order. - */ - Page findAllByTest_IdOrderByTestReport_StartDateDesc(Long testId, Pageable pageable); -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/repositories/TestScreenshotRepository.java b/backend/src/main/java/de/learnlib/alex/testing/repositories/TestScreenshotRepository.java deleted file mode 100644 index eaa09da6e..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/repositories/TestScreenshotRepository.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.repositories; - -import de.learnlib.alex.testing.entities.TestScreenshot; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** The repository for test screenshots. */ -@Repository -public interface TestScreenshotRepository extends JpaRepository { -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/rest/TestExecutionConfigResource.java b/backend/src/main/java/de/learnlib/alex/testing/rest/TestExecutionConfigResource.java deleted file mode 100644 index 717bce73e..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/rest/TestExecutionConfigResource.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.rest; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.security.AuthContext; -import de.learnlib.alex.testing.dao.TestExecutionConfigDAO; -import de.learnlib.alex.testing.entities.TestExecutionConfig; -import de.learnlib.alex.testing.entities.TestOptions; -import de.learnlib.alex.testing.entities.TestQueueItem; -import de.learnlib.alex.testing.services.TestService; -import java.util.List; -import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** Endpoints for handling test configs. */ -@RestController -@RequestMapping("/rest/projects/{projectId}/testConfigs") -public class TestExecutionConfigResource { - - private final AuthContext authContext; - private final TestExecutionConfigDAO testExecutionConfigDAO; - private final TestService testService; - - - @Autowired - public TestExecutionConfigResource(AuthContext authContext, - TestExecutionConfigDAO testExecutionConfigDAO, - TestService testService) { - this.authContext = authContext; - this.testExecutionConfigDAO = testExecutionConfigDAO; - this.testService = testService; - } - - @GetMapping( - value = "/{configId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity get(@PathVariable("projectId") Long projectId, - @PathVariable("configId") Long configId) { - final var user = authContext.getUser(); - final var config = testExecutionConfigDAO.get(user, projectId, configId); - return ResponseEntity.ok(config); - } - - /** - * Get all test configs in a project. - * - * @param projectId - * The id of the project. - * @return 200 and the created project on success. - */ - @GetMapping( - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> getAll(@PathVariable("projectId") Long projectId) { - final var user = authContext.getUser(); - final var configs = testExecutionConfigDAO.getAll(user, projectId); - return ResponseEntity.ok(configs); - } - - /** - * Create a test config. - * - * @param projectId - * The id of the project. - * @param config - * The config to create - * @return 201 and the created test config on success. - */ - @PostMapping( - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - - public ResponseEntity create( - @PathVariable("projectId") Long projectId, - @RequestBody TestExecutionConfig config - ) { - final var user = authContext.getUser(); - final var createdConfig = testExecutionConfigDAO.create(user, projectId, config); - return ResponseEntity.status(HttpStatus.CREATED).body(createdConfig); - } - - /** - * Update a test configuration - * - * @param projectId - * The ID of the project. - * @param configId - * The ID of the config to update. - * @param config - * The updated config object. - * @return The updated config object. - */ - @PutMapping( - value = "/{configId}", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity update( - @PathVariable("projectId") Long projectId, - @PathVariable("configId") Long configId, - @RequestBody TestExecutionConfig config - ) { - final var user = authContext.getUser(); - final var updatedConfig = testExecutionConfigDAO.update(user, projectId, configId, config); - return ResponseEntity.status(HttpStatus.OK).body(updatedConfig); - } - - @PostMapping( - value = "/{configId}/copy", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity copy(@PathVariable("projectId") Long projectId, - @PathVariable("configId") Long configId) { - final User user = authContext.getUser(); - final TestExecutionConfig copiedConfig = testExecutionConfigDAO.copy(user, projectId, configId); - return ResponseEntity.ok(copiedConfig); - } - - /** - * Delete a test config. - * - * @param projectId - * The id of the project. - * @param configId - * The id of the test config to delete. - * @return 204 on success. - */ - @DeleteMapping( - value = "/{configId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity delete(@PathVariable("projectId") Long projectId, - @PathVariable("configId") Long configId) { - final var user = authContext.getUser(); - testExecutionConfigDAO.delete(user, projectId, configId); - return ResponseEntity.noContent().build(); - } - - @PostMapping( - value = "/{configId}/run", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity run(@PathVariable("projectId") Long projectId, - @PathVariable("configId") Long configId, - @RequestBody(required = false) TestOptions testOptions) { - final var user = authContext.getUser(); - final var config = this.testExecutionConfigDAO.get(user, projectId, configId); - final var testRun = testService.start(user, projectId, config, testOptions); - return ResponseEntity.ok(testRun); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/rest/TestReportResource.java b/backend/src/main/java/de/learnlib/alex/testing/rest/TestReportResource.java deleted file mode 100644 index 5d81df1b6..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/rest/TestReportResource.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.rest; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.security.AuthContext; -import de.learnlib.alex.testing.dao.TestReportDAO; -import de.learnlib.alex.testing.entities.TestReport; -import de.learnlib.alex.testing.services.reporters.JUnitTestResultReporter; -import de.learnlib.alex.testing.services.reporters.TestResultReporter; -import java.util.List; -import javax.validation.ValidationException; -import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Sort; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -/** The resource for test reports. */ -@RestController -@RequestMapping("/rest/projects/{projectId}/tests/reports") -public class TestReportResource { - - private final AuthContext authContext; - private final TestReportDAO testReportDAO; - - @Autowired - public TestReportResource(AuthContext authContext, TestReportDAO testReportDAO) { - this.authContext = authContext; - this.testReportDAO = testReportDAO; - } - - /** - * Get all test reports. - * - * @param projectId - * The id of the project. - * @param page - * The page to get. - * @param size - * The number of items in a page. - * @return All test reports. - */ - @GetMapping( - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity get(@PathVariable("projectId") Long projectId, - @RequestParam(name = "page", defaultValue = "1") int page, - @RequestParam(name = "size", defaultValue = "25") int size) { - final User user = authContext.getUser(); - final PageRequest pr = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "startDate")); - final Page testReports = testReportDAO.getAll(user, projectId, pr); - return ResponseEntity.ok(testReports); - } - - /** - * Get a test report by ids id. - * - * @param projectId - * The id of the project. - * @param reportId - * The id of the report in the project. - * @param format - * The format to export the report to. - * @return The report. - */ - @GetMapping( - value = "/{reportId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity get(@PathVariable("projectId") Long projectId, - @PathVariable("reportId") Long reportId, - @RequestParam(name = "format", defaultValue = "") String format) { - final User user = authContext.getUser(); - final TestReport testReport = testReportDAO.get(user, projectId, reportId); - - switch (format) { - case "": - return ResponseEntity.ok(testReport); - case "junit": - final TestResultReporter reporter = new JUnitTestResultReporter(); - final String report = reporter.createReport(testReport); - - return ResponseEntity.status(HttpStatus.OK) - .header("Content-Type", "application/xml") - .body(report); - default: - throw new ValidationException("format " + format + " does not exist"); - } - } - - /** - * Get the latest test report. - * - * @param projectId - * The id of the project. - * @return 200 if a report is available, 204 otherwise. - */ - @GetMapping( - value = "/latest", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity getLatest(@PathVariable("projectId") Long projectId) { - final User user = authContext.getUser(); - final TestReport latestReport = testReportDAO.getLatest(user, projectId); - return latestReport == null ? ResponseEntity.noContent().build() : ResponseEntity.ok(latestReport); - } - - /** - * Deletes a single test report. - * - * @param projectId - * The id of the project. - * @param reportId - * The id of the report to delete. - * @return Status 204 - no content on success. - */ - @DeleteMapping( - value = "/{reportId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity delete(@PathVariable("projectId") Long projectId, - @PathVariable("reportId") Long reportId) { - final User user = authContext.getUser(); - testReportDAO.delete(user, projectId, reportId); - return ResponseEntity.noContent().build(); - } - - /** - * Deletes multiple test reports at once. - * - * @param projectId - * The id of the project. - * @param reportIds - * The ids of the reports to delete. - * @return Status 204 - no content on success. - */ - @DeleteMapping( - value = "/batch/{reportIds}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity delete(@PathVariable("projectId") Long projectId, - @PathVariable("reportIds") List reportIds) { - final User user = authContext.getUser(); - testReportDAO.delete(user, projectId, reportIds); - return ResponseEntity.noContent().build(); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/rest/TestResource.java b/backend/src/main/java/de/learnlib/alex/testing/rest/TestResource.java deleted file mode 100644 index ac35205a3..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/rest/TestResource.java +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.rest; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.entities.export.ExportableEntity; -import de.learnlib.alex.security.AuthContext; -import de.learnlib.alex.testing.dao.TestDAO; -import de.learnlib.alex.testing.entities.Test; -import de.learnlib.alex.testing.entities.TestExecutionConfig; -import de.learnlib.alex.testing.entities.TestOptions; -import de.learnlib.alex.testing.entities.TestQueueItem; -import de.learnlib.alex.testing.entities.TestReport; -import de.learnlib.alex.testing.entities.TestResult; -import de.learnlib.alex.testing.entities.TestStatus; -import de.learnlib.alex.testing.entities.export.TestsExportConfig; -import de.learnlib.alex.testing.events.TestEvent; -import de.learnlib.alex.testing.services.TestService; -import de.learnlib.alex.testing.services.export.TestsExporter; -import de.learnlib.alex.webhooks.services.WebhookService; -import java.util.List; -import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -/** - * REST endpoints for working with tests. - */ -@RestController -@RequestMapping("/rest/projects/{projectId}/tests") -public class TestResource { - - private final AuthContext authContext; - private final TestDAO testDAO; - private final TestService testService; - private final WebhookService webhookService; - private final TestsExporter testsExporter; - - @Autowired - public TestResource( - AuthContext authContext, - TestDAO testDAO, - TestService testService, - WebhookService webhookService, - TestsExporter testsExporter - ) { - this.authContext = authContext; - this.testDAO = testDAO; - this.testService = testService; - this.webhookService = webhookService; - this.testsExporter = testsExporter; - } - - /** - * Create a test. - * - * @param projectId - * The id of the project to create the test in. - * @param test - * The test to create. - * @return The created test. - */ - @PostMapping( - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity createTest(@PathVariable("projectId") Long projectId, - @RequestBody Test test) { - final var user = authContext.getUser(); - testDAO.create(user, projectId, test); - webhookService.fireEvent(user, new TestEvent.Created(test)); - return ResponseEntity.status(HttpStatus.CREATED).body(test); - } - - /** - * Create multiple tests at once. - * - * @param projectId - * The id of the project to create the tests in. - * @param tests - * The tests to create. - * @return The created tests. - */ - @PostMapping( - value = "/batch", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> createTests(@PathVariable("projectId") Long projectId, - @RequestBody List tests) { - final var user = authContext.getUser(); - final var createdTests = testDAO.create(user, projectId, tests); - webhookService.fireEvent(user, new TestEvent.CreatedMany(createdTests)); - return ResponseEntity.status(HttpStatus.CREATED).body(createdTests); - } - - /** - * Get a single test. - * - * @param projectId - * The id of the project. - * @param testId - * The id of the test. - * @return The test. - */ - @GetMapping( - value = "/{testId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity get(@PathVariable("projectId") Long projectId, - @PathVariable("testId") Long testId) { - final var user = authContext.getUser(); - final var test = testDAO.get(user, projectId, testId); - return ResponseEntity.ok(test); - } - - /** - * Get a single test. - * - * @param projectId - * The id of the project. - * @return The test. - */ - @GetMapping( - value = "/root", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity get(@PathVariable("projectId") Long projectId) { - final var user = authContext.getUser(); - final var root = testDAO.getRoot(user, projectId); - return ResponseEntity.ok(root); - } - - @GetMapping( - value = "/batch/{testIds}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> getMany(@PathVariable("projectId") Long projectId, - @PathVariable("testIds") List testIds) { - final var user = authContext.getUser(); - final var tests = testDAO.get(user, projectId, testIds); - return ResponseEntity.ok(tests); - } - - /** - * Executes a test run that can contains multiple tests. - * - * @param projectId - * The id of the project - * @param testConfig - * The configuration for the test - * @return A {@link TestReport}. - */ - @PostMapping( - value = "/execute", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity execute(@PathVariable("projectId") Long projectId, - @RequestBody TestExecutionConfig testConfig) { - final var user = authContext.getUser(); - final var testRun = testService.start(user, projectId, testConfig, null); - return ResponseEntity.ok(testRun); - } - - /** - * Get the status of the current test process. - * - * @param projectId - * The id of the project. - * @return Status 200 with a {@link TestStatus}. - */ - @GetMapping( - value = "/status", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity status(@PathVariable("projectId") Long projectId) { - final var user = authContext.getUser(); - final var status = testService.getStatus(user, projectId); - return ResponseEntity.ok(status); - } - - @PostMapping( - value = "/export", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity exportTests(@PathVariable("projectId") Long projectId, - @RequestBody TestsExportConfig config) - throws Exception { - final User user = authContext.getUser(); - final ExportableEntity exportedTests = testsExporter.export(user, projectId, config); - return ResponseEntity.ok(exportedTests); - } - - @PostMapping( - value = "/import", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> importTests(@PathVariable("projectId") Long projectId, - @RequestBody List tests) { - final var user = authContext.getUser(); - final var importedTests = testDAO.importTests(user, projectId, tests, null, null); - return ResponseEntity.ok(importedTests); - } - - /** - * Update a test. - * - * @param projectId - * The id of the project. - * @param testId - * The id of the test. - * @param test - * The updated test. - * @return The updated test. - */ - @PutMapping( - value = "/{testId}", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity update(@PathVariable("projectId") Long projectId, - @PathVariable("testId") Long testId, - @RequestBody Test test) { - final var user = authContext.getUser(); - final var updatedTest = testDAO.update(user, projectId, testId, test); - webhookService.fireEvent(user, new TestEvent.Updated(updatedTest)); - return ResponseEntity.ok(updatedTest); - } - - /** - * Move tests to another test suite. - * - * @param projectId - * The id of the project. - * @param testIds - * The ids of the tests to move. - * @param targetId - * The id of the target test suite. - * @return 200 If the tests have been moved successfully. - */ - @PutMapping( - value = "/batch/{testIds}/moveTo/{targetId}", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> move(@PathVariable("projectId") Long projectId, - @PathVariable("testIds") List testIds, - @PathVariable("targetId") Long targetId) { - final var user = authContext.getUser(); - final var movedTests = testDAO.move(user, projectId, testIds, targetId); - webhookService.fireEvent(user, new TestEvent.MovedMany(movedTests)); - return ResponseEntity.ok(movedTests); - } - - /** - * Delete a test. - * - * @param projectId - * The id of the project. - * @param testId - * The id of the test. - * @return An empty body if the test has been deleted. - */ - @DeleteMapping( - value = "/{testId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity delete(@PathVariable("projectId") Long projectId, - @PathVariable("testId") Long testId) { - final var user = authContext.getUser(); - testDAO.delete(user, projectId, testId); - webhookService.fireEvent(user, new TestEvent.Deleted(testId)); - return ResponseEntity.noContent().build(); - } - - @PostMapping( - value = "/abort/{reportId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity abort(@PathVariable("projectId") Long projectId, - @PathVariable("reportId") Long reportId) { - final var user = authContext.getUser(); - testService.abort(user, projectId, reportId); - return ResponseEntity.ok().build(); - } - - /** - * Deletes multiple tests. - * - * @param projectId - * The id of the project. - * @param testIds - * The ids of the tests to delete. - * @return An empty body if the project has been deleted. - */ - @DeleteMapping( - value = "/batch/{testIds}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity delete(@PathVariable("projectId") Long projectId, - @PathVariable("testIds") List testIds) { - final var user = authContext.getUser(); - testDAO.delete(user, projectId, testIds); - webhookService.fireEvent(user, new TestEvent.DeletedMany(testIds)); - return ResponseEntity.noContent().build(); - } - - /** - * Get all test results of a test. - * - * @param projectId - * The ID of the project. - * @param testId - * The ID of the test. - * @param page - * The page number. - * @param size - * The number of items in the page. - * @return All test results of a test. - */ - @GetMapping( - value = "/{testId}/results", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> getResults(@PathVariable("projectId") Long projectId, - @PathVariable("testId") Long testId, - @RequestParam(name = "page", defaultValue = "1") int page, - @RequestParam(name = "size", defaultValue = "25") int size) { - final var user = authContext.getUser(); - final var pr = PageRequest.of(page, size); - final var results = testDAO.getResults(user, projectId, testId, pr); - return ResponseEntity.ok(results); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/rest/TestResultResource.java b/backend/src/main/java/de/learnlib/alex/testing/rest/TestResultResource.java deleted file mode 100644 index cf25ed032..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/rest/TestResultResource.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.rest; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.security.AuthContext; -import de.learnlib.alex.testing.dao.TestReportDAO; -import de.learnlib.alex.testing.dao.TestResultDAO; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import javax.ws.rs.InternalServerErrorException; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.InputStreamResource; -import org.springframework.core.io.Resource; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/rest/projects/{projectId}/tests/reports/{reportId}/results") -public class TestResultResource { - - /** The security context containing the user of the request. */ - private final AuthContext authContext; - private final TestReportDAO testReportDAO; - private final TestResultDAO testResultDAO; - - @Autowired - public TestResultResource(AuthContext authContext, - TestReportDAO testReportDAO, - TestResultDAO testResultDAO) { - this.authContext = authContext; - this.testReportDAO = testReportDAO; - this.testResultDAO = testResultDAO; - } - - /** - * Get a test result by ids id. - * - * @param projectId - * The id of the project. - * @param resultId - * The id of the report in the project. - * @return The result. - */ - @GetMapping( - value = "/{resultId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity get(@PathVariable("projectId") Long projectId, - @PathVariable("reportId") Long reportId, - @PathVariable("resultId") Long resultId) { - final User user = authContext.getUser(); - final var result = testResultDAO.getByID(user, projectId, reportId, resultId); - return ResponseEntity.ok(result); - } - - @GetMapping( - value = "/{resultId}/screenshots/{screenshotName}" - ) - public ResponseEntity getScreenshot(@PathVariable("projectId") Long projectId, - @PathVariable("reportId") Long reportId, - @PathVariable("screenshotName") String screenshotName) { - final User user = authContext.getUser(); - - final File screenshot = testReportDAO.getScreenshot(user, projectId, reportId, screenshotName); - - final Resource resource = new FileSystemResource(screenshot); - return ResponseEntity.ok() - .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + screenshot.getName() + "\"") - .body(resource); - } - - @GetMapping( - value = "/{resultId}/screenshots/batch" - ) - public ResponseEntity getAllScreenshots(@PathVariable("projectId") Long projectId, - @PathVariable("reportId") Long reportId, - @PathVariable("resultId") Long resultId) { - final User user = authContext.getUser(); - - try { - final ByteArrayInputStream is = new ByteArrayInputStream(testReportDAO.getScreenshotsAsZip(user, projectId, reportId, resultId)); - final Resource resource = new InputStreamResource(is); - return ResponseEntity.ok() - .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"screenshots.zip\"") - .body(resource); - } catch (IOException e) { - throw new InternalServerErrorException("There was a problem generation the zip file."); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/services/TestExecutor.java b/backend/src/main/java/de/learnlib/alex/testing/services/TestExecutor.java deleted file mode 100644 index c47c7cdfe..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/services/TestExecutor.java +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.services; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.dao.ProjectEnvironmentDAO; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolStep; -import de.learnlib.alex.learning.services.connectors.ConnectorContextHandler; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.PreparedConnectorContextHandlerFactory; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import de.learnlib.alex.testing.entities.Test; -import de.learnlib.alex.testing.entities.TestCase; -import de.learnlib.alex.testing.entities.TestCaseResult; -import de.learnlib.alex.testing.entities.TestCaseStep; -import de.learnlib.alex.testing.entities.TestExecutionConfig; -import de.learnlib.alex.testing.entities.TestExecutionResult; -import de.learnlib.alex.testing.entities.TestResult; -import de.learnlib.alex.testing.entities.TestScreenshot; -import de.learnlib.alex.testing.entities.TestSuite; -import de.learnlib.alex.testing.entities.TestSuiteResult; -import java.io.File; -import java.io.IOException; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Service; -import org.springframework.util.FileCopyUtils; - -@Service -@Scope("prototype") -public class TestExecutor { - - private static final Logger logger = LoggerFactory.getLogger(TestExecutor.class); - - @Value("${alex.filesRootDir}") - private String filesRootDir; - private final ProjectEnvironmentDAO projectEnvironmentDAO; - private final PreparedConnectorContextHandlerFactory contextHandlerFactory; - - private Test currentTest; - private boolean aborted; - - @Autowired - public TestExecutor( - PreparedConnectorContextHandlerFactory contextHandlerFactory, - ProjectEnvironmentDAO projectEnvironmentDAO - ) { - this.contextHandlerFactory = contextHandlerFactory; - this.projectEnvironmentDAO = projectEnvironmentDAO; - - this.aborted = false; - } - - public void executeTests(User user, List tests, TestExecutionConfig testConfig, Map results) { - for (Test test : tests) { - currentTest = test; - if (aborted) { - break; - } - - if (test instanceof TestCase) { - executeTestCase(user, (TestCase) test, testConfig, results); - } else if (test instanceof TestSuite) { - executeTestSuite(user, (TestSuite) test, testConfig, results); - } - } - } - - /** - * Execute a test suite. - * - * @param user - * The user that executes the test suite. - * @param testSuite - * The test suite that is being executed. - * @param testConfig - * The config for the test. - * @param results - * The map with the test results. - * @return The updated test result map. - */ - public TestSuiteResult executeTestSuite(User user, TestSuite testSuite, TestExecutionConfig testConfig, - Map results) { - final TestSuiteResult tsResult = new TestSuiteResult(testSuite, 0L, 0L); - - final List testCases = testSuite.getTests().stream() - .filter(TestCase.class::isInstance) - .collect(Collectors.toList()); - - for (Test test : testCases) { - if (aborted) { - return tsResult; - } - final TestCaseResult result = executeTestCase(user, (TestCase) test, testConfig, results); - tsResult.add(result); - } - - final List testSuites = testSuite.getTests().stream() - .filter(TestSuite.class::isInstance) - .collect(Collectors.toList()); - - for (Test test : testSuites) { - if (aborted) { - return tsResult; - } - final TestSuiteResult result = executeTestSuite(user, (TestSuite) test, testConfig, results); - tsResult.add(result); - } - - results.put(testSuite.getId(), tsResult); - return tsResult; - } - - /** - * Executes a test case. - * - * @param user - * The user that executes the test suite. - * @param testCase - * The test case that is being executed. - * @param testConfig - * The config for the test. - * @param results - * The map with the test results. - * @return The updated test result map. - */ - public TestCaseResult executeTestCase(User user, TestCase testCase, TestExecutionConfig testConfig, - Map results) { - logger.info(LoggerMarkers.LEARNER, "Execute test[id={}] '{}'", testCase.getId(), testCase.getName()); - - final Symbol dummySymbol = new Symbol(); - dummySymbol.setName("dummy"); - dummySymbol.getSteps().add(new SymbolStep() { - @Override - public ExecuteResult execute(int i, ConnectorManager connectors) { - return new ExecuteResult(true); - } - }); - final ParameterizedSymbol dummyPSymbol = new ParameterizedSymbol(dummySymbol); - - final ProjectEnvironment env = projectEnvironmentDAO.getByID(user, testConfig.getEnvironmentId()); - - final ConnectorContextHandler ctxHandler = contextHandlerFactory - .createPreparedContextHandler(user, testCase.getProject(), testConfig.getDriverConfig(), dummyPSymbol, null) - .create(env); - - final long startTime = System.currentTimeMillis(); - final ConnectorManager connectors = ctxHandler.createContext(); - - final List outputs = new ArrayList<>(); - - boolean preSuccess = executePreSteps(connectors, testCase.getPreSteps()); - - // execute the steps as long as they do not fail - long failedStep = -1L; - - TestScreenshot beforeScreenshot = null; - - if (preSuccess) { - - beforeScreenshot = takeAndStoreScreenshot(testCase.getProject(), connectors.getConnector(WebSiteConnector.class), "pre"); - - for (int i = 0; i < testCase.getSteps().size(); i++) { - if (aborted) { - break; - } - - final TestCaseStep step = testCase.getSteps().get(i); - if (step.isDisabled()) { - outputs.add(new ExecuteResult(true, "Skipped")); - continue; - } - - final ExecuteResult result = executeStep(connectors, step); - outputs.add(result); - - final TestScreenshot stepScreenshot = takeAndStoreScreenshot( - testCase.getProject(), - connectors.getConnector(WebSiteConnector.class), - step.getId().toString() - ); - result.setTestScreenshot(stepScreenshot); - - if (step.getExpectedOutputMessage().equals("")) { - if (result.isSuccess() != step.isExpectedOutputSuccess()) { - failedStep = i; - break; - } - } else { - if (!result.getOutput().equals(step.getComputedOutput())) { - failedStep = i; - break; - } - } - } - } else { - failedStep = -2L; - } - - // the remaining steps after the failing step are not executed - while (outputs.size() < testCase.getSteps().size()) { - outputs.add(new ExecuteResult(false, "Not executed")); - } - - executePostSteps(connectors, testCase.getPostSteps()); - - connectors.dispose(); - connectors.post(); - final long time = System.currentTimeMillis() - startTime; - - final List sulOutputs = outputs.stream() - .map(TestExecutionResult::new) - .collect(Collectors.toList()); - - for (int i = 0; i < outputs.size(); i++) { - final TestCaseStep step = testCase.getSteps().get(i); - sulOutputs.get(i).setSymbol(step.getPSymbol().getSymbol()); - sulOutputs.get(i).setTestScreenshot(outputs.get(i).getTestScreenshot()); - } - - final TestCaseResult result = new TestCaseResult(testCase, sulOutputs, failedStep, time); - result.setBeforeScreenshot(beforeScreenshot); - results.put(testCase.getId(), result); - - logger.info(LoggerMarkers.LEARNER, "Finished executing test[id={}], passed=" + result.isPassed(), testCase.getId()); - return result; - } - - private TestScreenshot takeAndStoreScreenshot(Project project, WebSiteConnector webSiteConnector, String fileNameSuffix) { - - String directoryPath = filesRootDir + "/test_screenshots/" + project.getId().toString(); - - // check files structure - File testScreenshotBaseDirectory = Paths.get(directoryPath).toFile(); - if (!testScreenshotBaseDirectory.exists()) { - testScreenshotBaseDirectory.mkdirs(); - } - - final File screenshot = webSiteConnector.takeScreenshot(); - TestScreenshot testScreenshot = null; - if (screenshot != null) { - String filename = System.currentTimeMillis() + "_" + fileNameSuffix; - try { - FileCopyUtils.copy(screenshot, new File(directoryPath + "/" + filename + ".png")); - } catch (IOException e) { - e.printStackTrace(); - return null; - } - - testScreenshot = new TestScreenshot(); - testScreenshot.setFilename(filename); - } - - return testScreenshot; - } - - private boolean executePreSteps(ConnectorManager connectors, List preSteps) { - for (TestCaseStep preStep : preSteps) { - final ExecuteResult result = executeStep(connectors, preStep); - if (!result.isSuccess()) { - return false; - } - } - return true; - } - - private void executePostSteps(ConnectorManager connectors, List postSteps) { - for (TestCaseStep postStep : postSteps) { - executeStep(connectors, postStep); - } - } - - private ExecuteResult executeStep(ConnectorManager connectors, TestCaseStep step) { - try { - return step.execute(connectors); - } catch (Exception e) { - return new ExecuteResult(false); - } - } - - public Test getCurrentTest() { - return currentTest; - } - - public void abort() { - this.aborted = true; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/services/TestService.java b/backend/src/main/java/de/learnlib/alex/testing/services/TestService.java deleted file mode 100644 index 8603eb33d..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/services/TestService.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.services; - -import de.learnlib.alex.auth.dao.UserDAO; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.common.exceptions.ResourcesExhaustedException; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.learning.services.LearnerService; -import de.learnlib.alex.testing.dao.TestReportDAO; -import de.learnlib.alex.testing.entities.TestExecutionConfig; -import de.learnlib.alex.testing.entities.TestOptions; -import de.learnlib.alex.testing.entities.TestProcessQueueItem; -import de.learnlib.alex.testing.entities.TestQueueItem; -import de.learnlib.alex.testing.entities.TestReport; -import de.learnlib.alex.testing.entities.TestStatus; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import de.learnlib.alex.webhooks.dao.WebhookDAO; -import org.apache.shiro.authz.UnauthorizedException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.transaction.support.TransactionTemplate; - -/** The service that executes tests. */ -@Service -public class TestService { - - private final ApplicationContext applicationContext; - private final TestReportDAO testReportDAO; - private final ProjectDAO projectDAO; - private final LearnerService learnerService; - private final UserDAO userDAO; - private final TransactionTemplate transactionTemplate; - private final WebhookDAO webhookDAO; - - - /** The running testing threads (projectId -> TestThread). */ - private final Map testThreads; - - @Autowired - public TestService( - ApplicationContext applicationContext, - TestReportDAO testReportDAO, - ProjectDAO projectDAO, - @Lazy LearnerService learnerService, - @Lazy UserDAO userDAO, - TransactionTemplate transactionTemplate, - WebhookDAO webhookDAO) { - this.applicationContext = applicationContext; - this.testReportDAO = testReportDAO; - this.projectDAO = projectDAO; - this.learnerService = learnerService; - this.userDAO = userDAO; - this.transactionTemplate = transactionTemplate; - this.webhookDAO = webhookDAO; - - this.testThreads = new ConcurrentHashMap<>(); - } - - /** - * Starts a new test thread. - * - * @param user - * The user. - * @param projectId - * The ID of the project. - * @param config - * The config for the tests. - * @return A test status. - */ - public TestQueueItem start(User user, Long projectId, TestExecutionConfig config, TestOptions testOptions) { - final var project = projectDAO.getByID(user, projectId); - User userInDb = this.userDAO.getByID(user.getId()); - - final var createdReport = transactionTemplate.execute(t -> { - checkRunningProcesses(userInDb, projectId); - - final var r = new TestReport(); - r.setEnvironment(config.getEnvironment()); - r.setExecutedBy(user); - r.setProject(project); - r.setDescription(config.getDescription()); - - final var cr = testReportDAO.create(user, projectId, r); - t.flush(); - - return cr; - }); - - if (testOptions != null) { - // create onetime webhook - if (testOptions.getWebhook() != null) { - final var webhook = testOptions.getWebhook(); - webhook.setOnce(true); - this.webhookDAO.create(user, webhook); - } - } - - final var item = new TestProcessQueueItem( - user.getId(), - project.getId(), - createdReport.getId(), - config - ); - - if (testThreads.containsKey(project.getId())) { - final var testThread = testThreads.get(project.getId()); - testThread.add(item); - } else { - final var testThread = applicationContext.getBean(TestThread.class); - testThread.onFinished(() -> this.testThreads.remove(project.getId())); - - this.testThreads.put(project.getId(), testThread); - testThread.add(item); - testThread.start(); - } - - final var qi = new TestQueueItem(); - qi.setConfig(config); - qi.setReport(createdReport); - qi.setResults(new HashMap<>()); - - return qi; - } - - public boolean isActive(Long projectId) { - return this.testThreads.containsKey(projectId); - } - - @Transactional(rollbackFor = Exception.class) - public boolean hasRunningOrPendingTasks(User user, Long projectId) { - if (!isActive(projectId)) { - return false; - } - - final var testStatus = this.getStatus(user, projectId); - - List currentTestRunSingletonList = Optional.ofNullable(testStatus.getCurrentTestRun()) - .map(List::of) - .orElse(Collections.emptyList()); - - return Stream.of(currentTestRunSingletonList, testStatus.getTestRunQueue()) - .flatMap(List::stream) - .map(TestQueueItem::getReport) - .filter(Objects::nonNull) // check for not yet created reports - .map(TestReport::getStatus) - .anyMatch(status -> status.equals(TestReport.Status.IN_PROGRESS) || status.equals(TestReport.Status.PENDING)); - } - - @Transactional(rollbackFor = Exception.class) - public long getNumberOfUserOwnedTestProcesses(User user) { - return user.getProjectsOwner().stream() - .map(Project::getId) - .filter(projectId -> hasRunningOrPendingTasks(user, projectId)) - .count(); - } - - /** - * Gets the status of the active test process of a project. - * - * @param user - * The user. - * @param projectId - * The ID of the project. - * @return The status. - */ - @Transactional(rollbackFor = Exception.class) - public TestStatus getStatus(User user, Long projectId) { - final var project = projectDAO.getByID(user, projectId); - final var status = new TestStatus(); - - if (isActive(projectId)) { - final TestThread testThread = testThreads.get(project.getId()); - status.setTestRunQueue(testThread.getTestQueue().stream() - .map(item -> { - try { - final var i = new TestQueueItem(); - i.setReport(testReportDAO.get(user, projectId, item.reportId)); - i.setConfig(item.config); - return i; - } catch (NotFoundException e) { // the report has already been deleted - return null; - } - }) - .filter(Objects::nonNull) - .collect(Collectors.toList()) - ); - status.setCurrentTestRun(testThread.getCurrentTest()); - status.setCurrentTest(testThread.getTestExecutor().getCurrentTest()); - } - - return status; - } - - /** - * Abort the test process for a given report id. - * - * @param user - * The user. - * @param projectId - * The ID of the project. - * @param reportId - * The ID of the report to abort. - */ - @Transactional(rollbackFor = Exception.class) - public void abort(User user, Long projectId, Long reportId) { - final var project = projectDAO.getByID(user, projectId); - final var report = testReportDAO.get(user, projectId, reportId); - - final var isOwner = project.getOwners().stream() - .anyMatch(u -> u.equals(user)); - - if (!isOwner && report.getExecutedBy() != null && !report.getExecutedBy().equals(user)) { - throw new UnauthorizedException("You are not allowed to abort this test run."); - } - - if (testThreads.containsKey(projectId)) { - final TestThread testThread = testThreads.get(projectId); - testThread.abort(reportId); - } - } - - private void checkRunningProcesses(User user, Long projectId) { - var activeProcesses = getNumberOfUserOwnedTestProcesses(user) + learnerService.getNumberOfUserOwnedLearnProcesses(user); - if (activeProcesses >= user.getMaxAllowedProcesses()) { - // check if there are already running/pending tests in this project - if (!this.hasRunningOrPendingTasks(user, projectId)) { - throw new ResourcesExhaustedException("You are not allowed to have more than " - + user.getMaxAllowedProcesses() - + " concurrent test/learn processes."); - } - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/services/TestThread.java b/backend/src/main/java/de/learnlib/alex/testing/services/TestThread.java deleted file mode 100644 index 17331a24a..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/services/TestThread.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.services; - -import de.learnlib.alex.auth.dao.UserDAO; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.common.utils.LoggerMarkers; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.testing.dao.TestDAO; -import de.learnlib.alex.testing.dao.TestReportDAO; -import de.learnlib.alex.testing.entities.TestProcessQueueItem; -import de.learnlib.alex.testing.entities.TestQueueItem; -import de.learnlib.alex.testing.entities.TestReport; -import de.learnlib.alex.testing.entities.TestResult; -import de.learnlib.alex.testing.events.TestEvent; -import de.learnlib.alex.testing.events.TestExecutionStartedEventData; -import de.learnlib.alex.webhooks.services.WebhookService; -import java.util.ArrayList; -import java.util.Deque; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedDeque; -import java.util.concurrent.atomic.AtomicBoolean; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.transaction.support.TransactionTemplate; - -/** - * The thread that executes tests. There should ever only be one test per project. - */ -@Service -@Scope("prototype") -public class TestThread extends Thread { - - private static final Logger logger = LoggerFactory.getLogger(TestThread.class); - - /** Listener for when the test process finished. */ - public interface FinishedListener { - /** What to do when the test process finished. */ - void handleFinished(); - } - - private final WebhookService webhookService; - private final TestDAO testDAO; - private final TestReportDAO testReportDAO; - private final ProjectDAO projectDAO; - private final UserDAO userDAO; - private final TransactionTemplate transactionTemplate; - - /** The finished listener. */ - private FinishedListener finishedListener; - - public void onFinished(FinishedListener listener) { - this.finishedListener = listener; - } - - private final TestExecutor testExecutor; - - /** The user that executes the tests. */ - private User user; - - /** The project that is used. */ - private Project project; - - /** The current test report. */ - private TestReport report; - - /** The queue of tests to execute. */ - private final Deque testProcessQueue = new ConcurrentLinkedDeque<>(); - - /** The current test process queue item. */ - private TestProcessQueueItem currentTestProcessQueueItem; - - /** Test results of the current test process. */ - final Map results = new ConcurrentHashMap<>(); - - @Autowired - public TestThread( - WebhookService webhookService, - TestDAO testDAO, - TestReportDAO testReportDAO, - ProjectDAO projectDAO, - UserDAO userDAO, - TransactionTemplate transactionTemplate, - ApplicationContext applicationContext - ) { - this.webhookService = webhookService; - this.testDAO = testDAO; - this.testReportDAO = testReportDAO; - this.projectDAO = projectDAO; - this.userDAO = userDAO; - this.transactionTemplate = transactionTemplate; - this.testExecutor = applicationContext.getBean(TestExecutor.class); - } - - @Override - public void run() { - while (!testProcessQueue.isEmpty()) { - currentTestProcessQueueItem = testProcessQueue.poll(); - results.clear(); - - final var reportExists = new AtomicBoolean(true); - transactionTemplate.execute((t) -> { - user = userDAO.getByID(currentTestProcessQueueItem.userId); - project = projectDAO.getByID(user, currentTestProcessQueueItem.projectId); - try { - report = testReportDAO.get(user, project.getId(), currentTestProcessQueueItem.reportId); - } catch (NotFoundException e) { - // the report has been deleted, but the corresponding item is still in the queue - reportExists.set(false); - } - return null; - }); - - if (!reportExists.get() || report.getStatus().equals(TestReport.Status.ABORTED)) { - continue; - } - - try { - MDC.put("userId", String.valueOf(user.getId())); - MDC.put("projectId", String.valueOf(project.getId())); - - final var config = currentTestProcessQueueItem.config; - logger.info(LoggerMarkers.LEARNER, "Start executing tests: {}", config.getTestIds()); - - report = testReportDAO.updateStatus(report.getId(), TestReport.Status.IN_PROGRESS); - - // do not fire the event if the test is only called for testing purposes. - final TestExecutionStartedEventData data = new TestExecutionStartedEventData(project.getId(), config); - webhookService.fireEvent(user, new TestEvent.ExecutionStarted(data)); - - final var testsToExecute = testDAO.get(user, project.getId(), config.getTestIds()); - testExecutor.executeTests(user, testsToExecute, config, results); - - report = transactionTemplate.execute((t) -> { - report = testReportDAO.getByID(report.getId()); - report.setTestResults(new ArrayList<>(results.values())); - - if (!report.getStatus().equals(TestReport.Status.ABORTED)) { - report.setStatus(TestReport.Status.FINISHED); - } - - return testReportDAO.update(user, project.getId(), report.getId(), report); - }); - - webhookService.fireEvent(user, new TestEvent.ExecutionFinished(report)); - - logger.info(LoggerMarkers.LEARNER, "Successfully executed tests"); - } catch (Exception e) { - testReportDAO.updateStatus(report.getId(), TestReport.Status.ABORTED); - - logger.info(LoggerMarkers.LEARNER, "Could not execute all tests", e); - e.printStackTrace(); - } - } - - finishedListener.handleFinished(); - testProcessQueue.clear(); - - logger.info(LoggerMarkers.LEARNER, "Finished testing"); - MDC.remove("userId"); - MDC.remove("projectID"); - } - - @Transactional(rollbackFor = Exception.class) - public void abort(Long reportId) { - if (report != null) { - if (report.getId().equals(reportId)) { - report = testReportDAO.updateStatus(reportId, TestReport.Status.ABORTED); - testExecutor.abort(); - } else { - final var itemsToRemove = new ArrayList(); - for (var item : testProcessQueue) { - if (item.reportId.equals(reportId)) { - testReportDAO.updateStatus(item.reportId, TestReport.Status.ABORTED); - itemsToRemove.add(item); - } - } - itemsToRemove.forEach(testProcessQueue::remove); - } - } - } - - /** - * Add a test configuration to the queue. - * - * @param item - * The test configuration to add to the queue. - */ - public void add(TestProcessQueueItem item) { - this.testProcessQueue.addLast(item); - } - - public List getTestQueue() { - return new ArrayList<>(testProcessQueue); - } - - public TestQueueItem getCurrentTest() { - if (report != null) { - final var item = new TestQueueItem(); - item.setConfig(currentTestProcessQueueItem.config); - item.setResults(results); - item.setReport(report); - return item; - } - - return null; - } - - public TestExecutor getTestExecutor() { - return testExecutor; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/services/export/TestsExporter.java b/backend/src/main/java/de/learnlib/alex/testing/services/export/TestsExporter.java deleted file mode 100644 index 25cc92720..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/services/export/TestsExporter.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.services.export; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.databind.node.ObjectNode; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.SymbolParameter; -import de.learnlib.alex.data.entities.SymbolParameterValue; -import de.learnlib.alex.data.entities.export.ExportableEntity; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.data.services.export.EntityExporter; -import de.learnlib.alex.data.services.export.SymbolsExporter; -import de.learnlib.alex.testing.dao.TestDAO; -import de.learnlib.alex.testing.entities.Test; -import de.learnlib.alex.testing.entities.TestCaseStep; -import de.learnlib.alex.testing.entities.TestSuite; -import de.learnlib.alex.testing.entities.export.TestsExportConfig; -import de.learnlib.alex.testing.entities.export.TestsExportableEntity; -import de.learnlib.alex.testing.repositories.TestRepository; -import java.util.List; -import java.util.stream.Collectors; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(rollbackFor = Exception.class, readOnly = true) -public class TestsExporter extends EntityExporter { - - private final TestDAO testDAO; - private final TestRepository testRepository; - private final ProjectRepository projectRepository; - - @Autowired - public TestsExporter( - TestDAO testDAO, - TestRepository testRepository, - ProjectRepository projectRepository - ) { - super(); - - this.testDAO = testDAO; - this.testRepository = testRepository; - this.projectRepository = projectRepository; - - om.addMixIn(Test.class, IgnoreFieldsForTestMixin.class); - om.addMixIn(TestCaseStep.class, IgnoreIdFieldMixin.class); - om.addMixIn(ParameterizedSymbol.class, IgnoreIdFieldMixin.class); - om.addMixIn(SymbolParameter.class, IgnoreIdFieldMixin.class); - om.addMixIn(SymbolParameterValue.class, IgnoreIdFieldMixin.class); - - final SimpleModule module = new SimpleModule(); - module.addSerializer(new SymbolsExporter.ParameterizedSymbolSerializer(om, ParameterizedSymbol.class)); - om.registerModule(module); - } - - public ExportableEntity export(User user, Long projectId, TestsExportConfig config) throws Exception { - final Project project = projectRepository.findById(projectId).orElseThrow(() -> new NotFoundException("The project could not be found")); - - final List tests = testRepository.findAllByProject_IdAndIdIn(projectId, config.getTestIds()); - for (Test test : tests) { - testDAO.checkAccess(user, project, test); - } - - final TestsExportableEntity exportableTests = new TestsExportableEntity(version, om.readTree(om.writeValueAsString(tests))); - addTypeField(exportableTests.getTests()); - return exportableTests; - } - - public ExportableEntity exportAll(User user, Long projectId) throws Exception { - final Project project = projectRepository.findById(projectId).orElseThrow(() -> new NotFoundException("The project could not be found")); - final TestSuite root = (TestSuite) testRepository.findFirstByProject_IdOrderByIdAsc(projectId); - final List tests = testRepository.findAllByProject_IdAndIdIn(projectId, root.getTests().stream().map(Test::getId).collect(Collectors.toList())); - - testDAO.checkAccess(user, project, root); - final TestsExportableEntity exportableTests = new TestsExportableEntity(version, om.readTree(om.writeValueAsString(tests))); - addTypeField(exportableTests.getTests()); - return exportableTests; - } - - private void addTypeField(JsonNode tests) { - tests.elements().forEachRemaining(node -> { - final String type = node.has("tests") ? "suite" : "case"; - ((ObjectNode) node).put("type", type); - }); - } - - private abstract static class IgnoreFieldsForTestMixin extends IgnoreIdFieldMixin { - @JsonIgnore(value = false) - abstract Long getId(); - - @JsonIgnore - abstract Long getProjectId(); - - @JsonIgnore - abstract Long getParentId(); - - @JsonIgnore - abstract User getLastUpdatedBy(); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/services/reporters/JUnitTestResultReporter.java b/backend/src/main/java/de/learnlib/alex/testing/services/reporters/JUnitTestResultReporter.java deleted file mode 100644 index 933f9ae54..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/services/reporters/JUnitTestResultReporter.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.services.reporters; - -import de.learnlib.alex.testing.entities.Test; -import de.learnlib.alex.testing.entities.TestCaseResult; -import de.learnlib.alex.testing.entities.TestReport; -import de.learnlib.alex.testing.entities.TestSuiteResult; -import java.io.StringWriter; -import java.util.HashMap; -import java.util.Map; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -/** - * Creates a JUnit report of a test result. - */ -public class JUnitTestResultReporter extends TestResultReporter { - - /** - * Creates a report. - * - * @param report - * The config to create a report from. - * @return The serialized and formatted xml report as string. - */ - @Override - public String createReport(final TestReport report) { - try { - final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); - final DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); - final Document doc = docBuilder.newDocument(); - - // create the root element - final Element rootElement = doc.createElement("testsuites"); - rootElement.setAttribute("name", "Report (" + report.getStartDateAsString() + ")"); - doc.appendChild(rootElement); - - // create and collect all data from all test cases - // each test suite result contains the summed up statistics for all its direct child test cases - final Map testSuiteResultMap = new HashMap<>(); - report.getTestResults().stream() - .filter((r) -> r instanceof TestCaseResult) - .forEach((result) -> { - final Test parent = result.getTest().getParent(); - - // create a new test suite result if it has not been discovered yet - if (!testSuiteResultMap.containsKey(parent.getId())) { - final TestSuiteResult testSuiteResult = new TestSuiteResult(); - testSuiteResult.setTest(parent); - testSuiteResultMap.put(parent.getId(), testSuiteResult); - } - - // add the statistics of the test case to its test suite - testSuiteResultMap.get(parent.getId()).add((TestCaseResult) result); - }); - - // create xml elements for test suites and add them to the root element - final Map testSuiteElements = new HashMap<>(); - testSuiteResultMap.forEach((id, testSuiteResult) -> { - final Element el = createTestSuiteElement(doc, testSuiteResult); - testSuiteElements.put(id, el); - rootElement.appendChild(el); - }); - - // create xml elements for all test cases and append them to their corresponding test suite element - report.getTestResults().stream() - .filter((r) -> r instanceof TestCaseResult) - .forEach((result) -> { - final Element el = createTestCaseElement(doc, (TestCaseResult) result); - final Test parent = result.getTest().getParent(); - testSuiteElements.get(parent.getId()).appendChild(el); - }); - - // add the summed up statistics of the report to the root 'testsuites' element - rootElement.setAttribute("tests", String.valueOf(report.getNumTests())); - rootElement.setAttribute("failures", String.valueOf(report.getNumTestsFailed())); - rootElement.setAttribute("time", String.valueOf(report.getTime())); - - // create the xml - final Transformer transformer = TransformerFactory.newInstance().newTransformer(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - final DOMSource source = new DOMSource(doc); - final StringWriter stringWriter = new StringWriter(); - final StreamResult streamResult = new StreamResult(stringWriter); - transformer.transform(source, streamResult); - - return stringWriter.getBuffer().toString(); - } catch (Exception e) { - e.printStackTrace(); - return ""; - } - } - - private Element createTestSuiteElement(final Document doc, final TestSuiteResult suiteResult) { - final Element testSuiteEl = doc.createElement("testsuite"); - testSuiteEl.setAttribute("id", String.valueOf(suiteResult.getTest().getId())); - testSuiteEl.setAttribute("name", suiteResult.getTest().getName()); - testSuiteEl.setAttribute("tests", String.valueOf(suiteResult.getTestCasesRun())); - testSuiteEl.setAttribute("failures", String.valueOf(suiteResult.getTestCasesFailed())); - testSuiteEl.setAttribute("time", String.valueOf(suiteResult.getTime())); - return testSuiteEl; - } - - private Element createTestCaseElement(final Document doc, final TestCaseResult result) { - final Element testCaseEl = doc.createElement("testcase"); - testCaseEl.setAttribute("name", result.getTest().getName()); - testCaseEl.setAttribute("id", String.valueOf(result.getTest().getId())); - testCaseEl.setAttribute("time", String.valueOf(result.getTime())); - - if (!result.isPassed()) { - final Element failureEl = doc.createElement("failure"); - failureEl.setAttribute("message", result.getFailureMessage()); - testCaseEl.appendChild(failureEl); - } - - return testCaseEl; - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/testing/services/reporters/TestResultReporter.java b/backend/src/main/java/de/learnlib/alex/testing/services/reporters/TestResultReporter.java deleted file mode 100644 index 0bf56519d..000000000 --- a/backend/src/main/java/de/learnlib/alex/testing/services/reporters/TestResultReporter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.testing.services.reporters; - -import de.learnlib.alex.testing.entities.TestReport; - -/** - * Create a report of a test result. - * - * @param - * The type of the report. - */ -public abstract class TestResultReporter { - - /** - * Create a report of a test result. - * - * @param testReport - * The rest report. - * @return The report. - */ - public abstract T createReport(TestReport testReport); -} diff --git a/backend/src/main/java/de/learnlib/alex/webhooks/dao/WebhookDAO.java b/backend/src/main/java/de/learnlib/alex/webhooks/dao/WebhookDAO.java deleted file mode 100644 index da2af1426..000000000 --- a/backend/src/main/java/de/learnlib/alex/webhooks/dao/WebhookDAO.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.webhooks.dao; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.webhooks.entities.EventType; -import de.learnlib.alex.webhooks.entities.Webhook; -import de.learnlib.alex.webhooks.repositories.WebhookRepository; -import java.util.List; -import java.util.stream.Collectors; -import javax.validation.ValidationException; -import org.apache.shiro.authz.UnauthorizedException; -import org.hibernate.Hibernate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -/** - * The implementation of the {@link WebhookDAO}. - */ -@Service -@Transactional(rollbackFor = Exception.class) -public class WebhookDAO { - - /** - * The repository for webhooks. - */ - private final WebhookRepository webhookRepository; - - /** - * Constructor. - * - * @param webhookRepository - * The injected repository for webhooks. - */ - @Autowired - public WebhookDAO(WebhookRepository webhookRepository) { - this.webhookRepository = webhookRepository; - } - - public Webhook create(User user, Webhook webhook) { - if (webhookRepository.findByUser_IdAndUrl(user.getId(), webhook.getUrl()) != null) { - throw new ValidationException("A webhook under the given URL is already registered. " - + "Update the existing one instead."); - } - - webhook.setUser(user); - return webhookRepository.save(webhook); - } - - public List getAll(User user) { - final List webhooks = webhookRepository.findByUser_id(user.getId()); - webhooks.forEach(this::loadLazyRelations); - return webhooks; - } - - public List getByEvent(EventType event) { - final List webhooks = webhookRepository.findAllByEventsContains(event); - webhooks.forEach(this::loadLazyRelations); - return webhooks; - } - - public List getByUserAndEvent(User user, EventType event) { - final List webhooks = webhookRepository.findByUser_id(user.getId()).stream() - .filter(webhook -> webhook.getEvents().contains(event)) - .collect(Collectors.toList()); - webhooks.forEach(this::loadLazyRelations); - return webhooks; - } - - public void delete(User user, Long id) { - final Webhook webhook = webhookRepository.findById(id).orElse(null); - checkAccess(user, webhook); - webhookRepository.delete(webhook); - } - - public void delete(User user, List ids) { - for (Long id : ids) { - delete(user, id); - } - } - - public Webhook update(User user, Long webhookId, Webhook webhook) { - final Webhook webhookInDb = webhookRepository.findById(webhookId).orElse(null); - checkAccess(user, webhookInDb); - - // check if there is another webhook registered to the new URL. - final Webhook webhookWithSameUrl = webhookRepository.findByUser_IdAndUrl(user.getId(), webhook.getUrl()); - if (webhookWithSameUrl != null && !webhook.getId().equals(webhookWithSameUrl.getId())) { - throw new ValidationException("Another webhook is already registered to the URL."); - } - - webhookInDb.setEvents(webhook.getEvents()); - webhookInDb.setUrl(webhook.getUrl()); - webhookInDb.setName(webhook.getName()); - webhookInDb.setHeaders(webhook.getHeaders()); - webhookInDb.setMethod(webhook.getMethod()); - - return webhookRepository.save(webhookInDb); - } - - public void checkAccess(User user, Webhook webhook) { - if (webhook == null) { - throw new NotFoundException("The webhook does not exist."); - } - - if (!webhook.getUser().equals(user)) { - throw new UnauthorizedException("You are not allowed to access the webhook."); - } - } - - private void loadLazyRelations(Webhook webhook) { - Hibernate.initialize(webhook.getEvents()); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/webhooks/entities/Event.java b/backend/src/main/java/de/learnlib/alex/webhooks/entities/Event.java deleted file mode 100644 index ad6327b18..000000000 --- a/backend/src/main/java/de/learnlib/alex/webhooks/entities/Event.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.webhooks.entities; - -/** - * The event. - * - * @param - * The type of the data that is passed by the event. - */ -public abstract class Event { - - /** The data that is send to the receiver. */ - private T data; - - /** The name of the event. */ - private EventType eventType; - - /** - * Constructor. - * - * @param data - * {@link #data} - * @param eventType - * {@link #eventType} - */ - public Event(T data, EventType eventType) { - this.data = data; - this.eventType = eventType; - } - - public T getData() { - return data; - } - - public void setData(T data) { - this.data = data; - } - - public EventType getEventType() { - return eventType; - } - - public void setEventType(EventType eventType) { - this.eventType = eventType; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/webhooks/entities/EventType.java b/backend/src/main/java/de/learnlib/alex/webhooks/entities/EventType.java deleted file mode 100644 index 52d989b3c..000000000 --- a/backend/src/main/java/de/learnlib/alex/webhooks/entities/EventType.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.webhooks.entities; - -/** The interface all concrete event type enums should implement. */ -public enum EventType { - - /** Fired when the learner finished. */ - LEARNER_FINISHED, - - /** Fired when the learner resumed learning. */ - LEARNER_RESUMED, - - /** Fired when the learner started. */ - LEARNER_STARTED, - - /** Fired when a project is created. */ - PROJECT_CREATED, - - /** Fired when a project is deleted. */ - PROJECT_DELETED, - - /** Fired when a project is updated. */ - PROJECT_UPDATED, - - /** Fired when a LTS formula is created. */ - LTS_FORMULA_CREATED, - - /** Fired when a LTS formula is updated. */ - LTS_FORMULA_UPDATED, - - /** Fired when a LTS formula is deleted. */ - LTS_FORMULA_DELETED, - - /** Fired when LTS formulas are deleted at once. */ - LTS_FORMULAS_DELETED, - - /** Fired when LTS formulas have been checked. */ - LTS_FORMULAS_CHECKED, - - /** Fired when the application settings are updated. */ - SETTINGS_UPDATED, - - /** Fired when a symbol is created. */ - SYMBOL_CREATED, - - /** Fired when a symbol is updated, moved or hidden. */ - SYMBOL_UPDATED, - - /** Fired when a symbol is deleted permanently. */ - SYMBOL_DELETED, - - /** Fired when multiple symbols are created. */ - SYMBOLS_CREATED, - - /** Fired when multiple symbols are updated, moved or hidden. */ - SYMBOLS_UPDATED, - - /** Fired when multiple symbols are deleted. */ - SYMBOLS_DELETED, - - /** Fired when a symbol group is created. */ - SYMBOL_GROUP_CREATED, - - /** Fired when a symbol group is deleted. */ - SYMBOL_GROUP_DELETED, - - /** Fired when a symbol group is updated. */ - SYMBOL_GROUP_UPDATED, - - /** Fired when a symbol group is moved. */ - SYMBOL_GROUP_MOVED, - - /** Fired when multiple symbol groups are created. */ - SYMBOL_GROUPS_CREATED, - - /** Fired when a test case or test suite is created. */ - TEST_CREATED, - - /** Fired when a test case or test suite is updated. */ - TEST_UPDATED, - - /** Fired when a test case or test suite is deleted. */ - TEST_DELETED, - - /** Fired when the test execution finished. */ - TEST_EXECUTION_FINISHED, - - /** Fired when the test execution started. */ - TEST_EXECUTION_STARTED, - - /** Fired when multiple tests are created. */ - TESTS_CREATED, - - /** Fired when multiple tests are deleted. */ - TESTS_DELETED, - - /** Fired when tests are moved to another test suite. */ - TESTS_MOVED, - - /** Fired when a user is deleted. */ - USER_DELETED, - - /** Fired when the user updated its credentials. */ - USER_CREDENTIALS_UPDATED, - - /** Fired when the role of the user is updated. */ - USER_ROLE_UPDATED -} diff --git a/backend/src/main/java/de/learnlib/alex/webhooks/entities/Webhook.java b/backend/src/main/java/de/learnlib/alex/webhooks/entities/Webhook.java deleted file mode 100644 index a6e6f25f1..000000000 --- a/backend/src/main/java/de/learnlib/alex/webhooks/entities/Webhook.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.webhooks.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import de.learnlib.alex.auth.entities.User; -import org.hibernate.annotations.Type; -import org.springframework.util.SerializationUtils; - -import javax.persistence.Column; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Lob; -import javax.persistence.ManyToOne; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Objects; - -/** - * Webhook. - */ -@Entity -@JsonPropertyOrder(alphabetic = true) -public class Webhook implements Serializable { - - public enum Method { - - GET, - POST, - PUT, - DELETE - - } - - private static final long serialVersionUID = 2533300421211466078L; - - /** The id of the webhook. */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - /** The url to send data to. */ - @NotNull - @Pattern(regexp = "^https?://.+?") - private String url; - - /** The name associated with the webhook. */ - @NotBlank - private String name; - - /** The user that registered the webhook. */ - @ManyToOne(fetch = FetchType.EAGER, optional = false) - @JsonIgnore - private User user; - - /** The event that triggers the webhook. */ - @ElementCollection - @NotEmpty - private List events; - - @Lob - @Column(columnDefinition = "BYTEA") - @Type(type = "org.hibernate.type.BinaryType") - private byte[] headers; - - @NotNull - private Method method; - - @JsonIgnore - @NotNull - private boolean once = false; - - /** Constructor. */ - public Webhook() { - this.events = new ArrayList<>(); - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; - } - - @JsonProperty("user") - public Long getUserId() { - return user.getId(); - } - - @JsonProperty("user") - public void setUserId(Long userId) { - user = new User(userId); - } - - public List getEvents() { - return events; - } - - public void setEvents(List events) { - this.events = events; - } - - public HashMap getHeaders() { - if (headers == null) { - return new HashMap<>(); - } - return (HashMap) SerializationUtils.deserialize(headers); - } - - public void setHeaders(HashMap headers) { - this.headers = SerializationUtils.serialize(headers); - } - - public Webhook.Method getMethod() { - return method; - } - - public void setMethod(Webhook.Method method) { - this.method = method; - } - - @JsonIgnore - public boolean getOnce() { - return once; - } - - @JsonIgnore - public void setOnce(boolean once) { - this.once = once; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof Webhook)) { - return false; - } - Webhook webhook = (Webhook) o; - return Objects.equals(id, webhook.id); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } - - @Override - public String toString() { - return "Webhook{" - + "id=" + id - + ", url='" + url + '\'' - + ", name='" + name + '\'' - + ", user=" + user - + '}'; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/webhooks/repositories/WebhookRepository.java b/backend/src/main/java/de/learnlib/alex/webhooks/repositories/WebhookRepository.java deleted file mode 100644 index 0976d408d..000000000 --- a/backend/src/main/java/de/learnlib/alex/webhooks/repositories/WebhookRepository.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.webhooks.repositories; - -import de.learnlib.alex.webhooks.entities.EventType; -import de.learnlib.alex.webhooks.entities.Webhook; -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -/** The repository for webhooks. */ -@Repository -public interface WebhookRepository extends JpaRepository { - - /** - * Get a webhook by user id and webhook url. - * - * @param userId - * The id of the user. - * @param url - * The url of the webhook. - * @return The webhook. - */ - Webhook findByUser_IdAndUrl(Long userId, String url); - - /** - * Get all webhooks of a user. - * - * @param userId - * The id of the user. - * @return The list of webhooks. - */ - List findByUser_id(Long userId); - - List findAllByEventsContains(EventType event); -} diff --git a/backend/src/main/java/de/learnlib/alex/webhooks/rest/WebhookResource.java b/backend/src/main/java/de/learnlib/alex/webhooks/rest/WebhookResource.java deleted file mode 100644 index b6e38a360..000000000 --- a/backend/src/main/java/de/learnlib/alex/webhooks/rest/WebhookResource.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.webhooks.rest; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.security.AuthContext; -import de.learnlib.alex.webhooks.dao.WebhookDAO; -import de.learnlib.alex.webhooks.entities.EventType; -import de.learnlib.alex.webhooks.entities.Webhook; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; -import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * The resource for webhooks. - */ -@RestController -@RequestMapping("/rest/webhooks") -public class WebhookResource { - - private final AuthContext authContext; - private final WebhookDAO webhookDAO; - - /** - * Constructor. - * - * @param webhookDAO - * The {@link WebhookDAO} to use. - */ - @Autowired - public WebhookResource(AuthContext authContext, WebhookDAO webhookDAO) { - this.authContext = authContext; - this.webhookDAO = webhookDAO; - } - - /** - * Create a new webhook. - * - * @param webhook - * The webhook to create. - * @return The created webhook. - */ - @PostMapping( - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity create(@RequestBody Webhook webhook) { - final User user = authContext.getUser(); - final Webhook createdWebhook = webhookDAO.create(user, webhook); - return ResponseEntity.ok(createdWebhook); - } - - /** - * Get all webhooks for the user that is logged in. - * - * @return The list of registered webhooks. - */ - @GetMapping( - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> get() { - final User user = authContext.getUser(); - final List webhooks = webhookDAO.getAll(user); - return ResponseEntity.ok(webhooks); - } - - /** - * Update a webhook. - * - * @param webhookId - * The ID of the webhook to update. - * @param webhook - * The updated webhook. - * @return The updated webhook on success. - */ - @PutMapping( - value = "/{webhookId}", - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity update(@PathVariable("webhookId") Long webhookId, @RequestBody Webhook webhook) { - final User user = authContext.getUser(); - final Webhook updatedWebhook = webhookDAO.update(user, webhookId, webhook); - return ResponseEntity.ok(updatedWebhook); - } - - /** - * Delete a webhook. - * - * @param webhookId - * The id of the webhook. - * @return No no content on success. - */ - @DeleteMapping( - value = "/{webhookId}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity delete(@PathVariable("webhookId") Long webhookId) { - final User user = authContext.getUser(); - webhookDAO.delete(user, webhookId); - return ResponseEntity.noContent().build(); - } - - /** - * Deletes multiple webhooks at once. - * - * @param webhookIds - * The list of ids of the webhooks to delete. - * @return Not content on success. - */ - @DeleteMapping( - value = "/batch/{webhookIds}", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity delete(@PathVariable("webhookIds") List webhookIds) { - final User user = authContext.getUser(); - webhookDAO.delete(user, webhookIds); - return ResponseEntity.noContent().build(); - } - - /** - * Get all available events a user can subscribe to. - * - * @return All available events. - */ - @GetMapping( - value = "/events", - produces = MediaType.APPLICATION_JSON - ) - public ResponseEntity> getEvents() { - final List eventTypes = new ArrayList<>(EnumSet.allOf(EventType.class)); - return ResponseEntity.ok(eventTypes); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/webhooks/services/WebhookService.java b/backend/src/main/java/de/learnlib/alex/webhooks/services/WebhookService.java deleted file mode 100644 index cd00b66cf..000000000 --- a/backend/src/main/java/de/learnlib/alex/webhooks/services/WebhookService.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.webhooks.services; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.webhooks.dao.WebhookDAO; -import de.learnlib.alex.webhooks.entities.Event; -import de.learnlib.alex.webhooks.entities.Webhook; -import de.learnlib.alex.webhooks.repositories.WebhookRepository; -import org.glassfish.jersey.client.ClientProperties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * The service that emits events to all remote subscribers. - */ -@Service -public class WebhookService { - - private static final Logger logger = LoggerFactory.getLogger(WebhookService.class); - - /** The client timeout. */ - private static final int READ_CONNECT_TIMEOUT = 3000; - - /** The maximum number of threads to use for sending http requests. */ - private static final int MAX_THREADS = 4; - - /** HTTP client. */ - private final Client client; - - /** The webhook DAO to use. */ - private final WebhookDAO webhookDAO; - - private final WebhookRepository webhookRepository; - - /** The thread executor for webhooks. */ - private final ExecutorService executorService; - - private final ObjectMapper objectMapper; - - @Autowired - public WebhookService(WebhookDAO webhookDAO, WebhookRepository webhookRepository, ObjectMapper objectMapper) { - this.webhookDAO = webhookDAO; - this.webhookRepository = webhookRepository; - this.objectMapper = objectMapper; - this.client = ClientBuilder.newClient() - .property(ClientProperties.READ_TIMEOUT, READ_CONNECT_TIMEOUT) - .property(ClientProperties.CONNECT_TIMEOUT, READ_CONNECT_TIMEOUT); - - this.executorService = Executors.newFixedThreadPool(MAX_THREADS); - } - - /** - * Sends the event to all subscribers. - * - * @param user - * The user under which the event occurred. - * @param event - * The event that occurred. - * @param - * The type of the event. - */ - public void fireEvent(User user, Event event) { - final List webhooks = webhookDAO.getByUserAndEvent(user, event.getEventType()); - triggerWebhooks(event, webhooks); - } - - /** - * Sends the event to all subscribers. - * - * @param event - * The event that occurred. - * @param - * The type of the event. - */ - public void fireEvent(Event event) { - final List webhooks = webhookDAO.getByEvent(event.getEventType()); - triggerWebhooks(event, webhooks); - } - - private void triggerWebhooks(Event event, List webhooks) { - for (final Webhook webhook : webhooks) { - executorService.submit(() -> { - try { - logger.info("Send {} to {} {}.", event, webhook.getMethod(), webhook.getUrl()); - var request = client.target(webhook.getUrl()).request(); - - // set header - for (var header : webhook.getHeaders().entrySet()) { - request = request.header(header.getKey(), header.getValue()); - } - - final var body = objectMapper.writeValueAsString(event); - final var bodyEntity = Entity.entity(body, MediaType.APPLICATION_JSON); - - final var response = switch (webhook.getMethod()) { - case GET -> request.get(); - case POST -> request.post(bodyEntity); - case PUT -> request.put(bodyEntity); - case DELETE -> request.delete(); - }; - - logger.info("Receive response from {} {} with status {}.", webhook.getMethod(), webhook.getUrl(), response.getStatus()); - } catch (Exception e) { - e.printStackTrace(); - } - }); - - if (webhook.getOnce()) { - final Webhook webhookInDB = webhookRepository.findById(webhook.getId()).orElse(null); - this.webhookRepository.delete(webhookInDB); - } - - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/websocket/WebSocketAuthChannelInterceptor.java b/backend/src/main/java/de/learnlib/alex/websocket/WebSocketAuthChannelInterceptor.java deleted file mode 100644 index 5e15627c8..000000000 --- a/backend/src/main/java/de/learnlib/alex/websocket/WebSocketAuthChannelInterceptor.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.websocket; - -import de.learnlib.alex.security.AuthenticationProvider; -import org.apache.shiro.authz.UnauthorizedException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.simp.stomp.StompCommand; -import org.springframework.messaging.simp.stomp.StompHeaderAccessor; -import org.springframework.messaging.support.ChannelInterceptor; -import org.springframework.messaging.support.MessageHeaderAccessor; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.stereotype.Component; - -/** - * Custom ChannelInterceptor that tries to authenticate a newly established - * Websocket connection over Stomp on the Stomp Connect Frame. - */ -@Component -public class WebSocketAuthChannelInterceptor implements ChannelInterceptor { - - private final AuthenticationProvider authenticationProvider; - - @Autowired - public WebSocketAuthChannelInterceptor(AuthenticationProvider authenticationProvider) { - this.authenticationProvider = authenticationProvider; - } - - @Override - public Message preSend(Message message, MessageChannel channel) { - var accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class); - if (StompCommand.CONNECT.equals(accessor.getCommand())) { - try { - var jwt = accessor.getFirstNativeHeader("Authorization"); - var usernamePasswordAuthToken = (UsernamePasswordAuthenticationToken) authenticationProvider.getAuthentication(jwt); - - if (usernamePasswordAuthToken.getAuthorities().contains(new SimpleGrantedAuthority("ANONYMOUS"))) { - throw new UnauthorizedException("Cannot get authorized."); - } - - accessor.setUser(usernamePasswordAuthToken); - } catch (Exception e) { - throw new UnauthorizedException("Cannot get authorized."); - } - } - return message; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/websocket/WebSocketConfig.java b/backend/src/main/java/de/learnlib/alex/websocket/WebSocketConfig.java deleted file mode 100644 index dd27f021a..000000000 --- a/backend/src/main/java/de/learnlib/alex/websocket/WebSocketConfig.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.websocket; - -import de.learnlib.alex.websocket.services.WebSocketService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Lazy; -import org.springframework.messaging.simp.config.MessageBrokerRegistry; -import org.springframework.web.socket.CloseStatus; -import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.WebSocketSession; -import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; -import org.springframework.web.socket.config.annotation.StompEndpointRegistry; -import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; -import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration; -import org.springframework.web.socket.handler.WebSocketHandlerDecorator; - -@Configuration -@EnableWebSocketMessageBroker -public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { - - @Override - public void configureMessageBroker(MessageBrokerRegistry config) { - config.enableSimpleBroker("/queue"); - config.setApplicationDestinationPrefixes("/app"); - config.setPreservePublishOrder(true); - } - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry.addEndpoint("/rest/ws/stomp").setAllowedOriginPatterns("*").withSockJS(); - } - - @Override - public void configureWebSocketTransport(WebSocketTransportRegistration registry) { - registry.addDecoratorFactory(webSocketHandler -> customWebSocketHandlerDecorator(webSocketHandler)); - } - - @Bean - public WebSocketHandlerDecorator customWebSocketHandlerDecorator(WebSocketHandler webSocketHandler) { - return new CustomWebSocketHandlerDecoratorImpl(webSocketHandler); - } - - class CustomWebSocketHandlerDecoratorImpl extends WebSocketHandlerDecorator { - - @Autowired - @Lazy - private WebSocketService webSocketService; - - public CustomWebSocketHandlerDecoratorImpl(WebSocketHandler delegate) { - super(delegate); - } - - @Override - public void afterConnectionEstablished(final WebSocketSession session) throws Exception { - this.webSocketService.addWebSocketSession(session); - super.afterConnectionEstablished(session); - } - - @Override - public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { - this.webSocketService.removeWebSocketSession(session.getId()); - super.afterConnectionClosed(session, closeStatus); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/websocket/WebSocketSecurityConfig.java b/backend/src/main/java/de/learnlib/alex/websocket/WebSocketSecurityConfig.java deleted file mode 100644 index 6335ee3ff..000000000 --- a/backend/src/main/java/de/learnlib/alex/websocket/WebSocketSecurityConfig.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.websocket; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.messaging.simp.config.ChannelRegistration; -import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; - -/** - * To ensure that this authentication configuration is ordered ahead of Spring's Security, - * it is marked with @Order(Ordered.HIGHEST_PRECEDENCE + 99) as suggested by the spring boot documentation. - */ -@Configuration -@Order(Ordered.HIGHEST_PRECEDENCE + 99) -public class WebSocketSecurityConfig implements WebSocketMessageBrokerConfigurer { - - private final WebSocketAuthChannelInterceptor webSocketAuthChannelInterceptor; - - @Autowired - public WebSocketSecurityConfig(WebSocketAuthChannelInterceptor webSocketAuthChannelInterceptor) { - this.webSocketAuthChannelInterceptor = webSocketAuthChannelInterceptor; - } - - @Override - public void configureClientInboundChannel(ChannelRegistration registration) { - registration.interceptors(webSocketAuthChannelInterceptor); - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/websocket/entities/WebSocketMessage.java b/backend/src/main/java/de/learnlib/alex/websocket/entities/WebSocketMessage.java deleted file mode 100644 index d97ff84a8..000000000 --- a/backend/src/main/java/de/learnlib/alex/websocket/entities/WebSocketMessage.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.websocket.entities; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import de.learnlib.alex.auth.entities.User; - -public class WebSocketMessage { - - @JsonIgnore - private User user; - - @JsonIgnore - private String sessionId; - - private String type; - - private String entity; - - private String content; - - public User getUser() { - return this.user; - } - - public void setUser(User user) { - this.user = user; - } - - public String getSessionId() { - return this.sessionId; - } - - public void setSessionId(String sessionId) { - this.sessionId = sessionId; - } - - public String getType() { - return this.type; - } - - public void setType(String type) { - this.type = type; - } - - public String getEntity() { - return this.entity; - } - - public void setEntity(String entity) { - this.entity = entity; - } - - public String getContent() { - return this.content; - } - - public void setContent(String content) { - this.content = content; - } -} diff --git a/backend/src/main/java/de/learnlib/alex/websocket/message/WebSocketController.java b/backend/src/main/java/de/learnlib/alex/websocket/message/WebSocketController.java deleted file mode 100644 index 03659aebf..000000000 --- a/backend/src/main/java/de/learnlib/alex/websocket/message/WebSocketController.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.websocket.message; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.jayway.jsonpath.JsonPath; -import de.learnlib.alex.security.AuthContext; -import de.learnlib.alex.websocket.entities.WebSocketMessage; -import de.learnlib.alex.websocket.services.WebSocketService; -import de.learnlib.alex.websocket.services.enums.WebSocketServiceEnum; -import java.io.IOException; -import java.security.Principal; -import javax.ws.rs.core.MediaType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.messaging.handler.annotation.MessageMapping; -import org.springframework.messaging.handler.annotation.Payload; -import org.springframework.messaging.simp.SimpAttributesContextHolder; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.ResponseStatus; - -@Controller -public class WebSocketController { - - private final WebSocketService webSocketService; - - private final AuthContext authContext; - - private final ObjectMapper objectMapper; - - @Autowired - public WebSocketController(WebSocketService webSocketService, AuthContext authContext, ObjectMapper objectMapper) { - this.webSocketService = webSocketService; - this.authContext = authContext; - this.objectMapper = objectMapper; - } - - @MessageMapping("/send/event") - public void onIncomingEvent(@Payload String event, Principal userPrincipal) { - WebSocketMessage msg; - - try { - msg = objectMapper.readValue(event, WebSocketMessage.class); - if (msg.getEntity() == null || msg.getType() == null) { - throw new IOException(); - } - webSocketService.processIncomingMessage(msg, userPrincipal); - } catch (IOException e) { - final WebSocketMessage error = new WebSocketMessage(); - error.setEntity(WebSocketServiceEnum.WEBSOCKET_SERVICE.name()); - error.setType(WebSocketServiceEnum.ERROR.name()); - - final ObjectNode content = objectMapper.createObjectNode(); - content.put("description", "Received malformed WebSocketMessage."); - content.put("message", event); - error.setContent(content.toString()); - - this.webSocketService.sendError(SimpAttributesContextHolder.currentAttributes().getSessionId(), error); - } - } - - @ResponseStatus(code = HttpStatus.NO_CONTENT) - @PostMapping( - value = "/rest/ws/disconnect", - consumes = MediaType.APPLICATION_JSON - ) - public void onDisconnect(@RequestBody String data) { - final String sessionId = JsonPath.read(data, "$.sessionId"); - final long userId = this.webSocketService.getUserIdBySessionId(sessionId); - - if (authContext.getUser().getId() == userId) { - this.webSocketService.closeSession(sessionId); - } - } - -} diff --git a/backend/src/main/java/de/learnlib/alex/websocket/services/ProjectPresenceService.java b/backend/src/main/java/de/learnlib/alex/websocket/services/ProjectPresenceService.java deleted file mode 100644 index 809bab778..000000000 --- a/backend/src/main/java/de/learnlib/alex/websocket/services/ProjectPresenceService.java +++ /dev/null @@ -1,429 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.websocket.services; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import de.learnlib.alex.auth.dao.UserDAO; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.websocket.entities.WebSocketMessage; -import de.learnlib.alex.websocket.services.enums.ProjectPresenceServiceEnum; -import de.learnlib.alex.websocket.services.enums.WebSocketServiceEnum; -import io.reactivex.rxjava3.disposables.Disposable; -import java.awt.Color; -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.locks.ReentrantLock; -import java.util.stream.Collectors; -import java.util.stream.IntStream; -import javax.annotation.PreDestroy; -import org.apache.shiro.authz.UnauthorizedException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -/** - * Service class which tracks user presences in projects. - */ -@Service -@Transactional(rollbackFor = Exception.class) -public class ProjectPresenceService { - - /** - * To ensure non concurrent access over multiple data structures an explicit lock is used. - * This lock is 'fair' in a way that it respects the order of waiting threads when granting access. - */ - private final ReentrantLock lock = new ReentrantLock(true); - - private final ObjectMapper objectMapper; - - private final WebSocketService webSocketService; - - private final ProjectDAO projectDAO; - - private final ProjectRepository projectRepository; - - private final UserDAO userDAO; - - /** A map which stores the ProjectPresenceStatus objects with the projectId as the key. */ - private final Map projectPresences; - - /** Shortcut mapping for easier access given the corresponding sessionId. */ - private final Map sessionMap; - - /** Shortcut mapping for easier access given the corresponding userId. */ - private final Map> userMap; - - private final Set disposables; - - @Autowired - public ProjectPresenceService(WebSocketService webSocketService, - ProjectDAO projectDAO, - ProjectRepository projectRepository, - UserDAO userDAO, - ObjectMapper objectMapper) { - this.webSocketService = webSocketService; - this.projectDAO = projectDAO; - this.projectRepository = projectRepository; - this.userDAO = userDAO; - this.objectMapper = objectMapper; - - this.disposables = new HashSet<>(); - this.projectPresences = new HashMap<>(); - this.sessionMap = new HashMap<>(); - this.userMap = new HashMap<>(); - - disposables.add( - this.webSocketService.register( - message -> message.getEntity().equals(ProjectPresenceServiceEnum.PROJECT_PRESENCE_SERVICE.name()) - && message.getType().equals(ProjectPresenceServiceEnum.USER_ENTERED.name())) - .subscribe(this::userEnteredProject) - ); - disposables.add( - this.webSocketService.register( - message -> message.getEntity().equals(ProjectPresenceServiceEnum.PROJECT_PRESENCE_SERVICE.name()) - && message.getType().equals(ProjectPresenceServiceEnum.USER_LEFT.name())) - .subscribe(this::userLeftProject) - ); - disposables.add( - this.webSocketService.register( - message -> message.getEntity().equals(WebSocketServiceEnum.WEBSOCKET_SERVICE_INTERNAL.name()) - && message.getType().equals(WebSocketServiceEnum.SESSION_DISCONNECT.name())) - .subscribe(this::sessionDisconnect) - ); - disposables.add( - this.webSocketService.register( - message -> message.getEntity().equals(ProjectPresenceServiceEnum.PROJECT_PRESENCE_SERVICE.name()) - && message.getType().equals(ProjectPresenceServiceEnum.STATUS_REQUEST.name())) - .subscribe(this::statusRequest) - ); - } - - public void userEnteredProject(WebSocketMessage message) { - lock.lock(); - - try { - final ObjectNode content = (ObjectNode) objectMapper.readTree(message.getContent()); - - final long userId = message.getUser().getId(); - final long projectId = content.get("projectId").asLong(); - final String sessionId = message.getSessionId(); - - /* session already was used in another project */ - Optional.ofNullable(sessionMap.get(sessionId)) - .ifPresent(projectPresenceStatus -> { - if (projectPresenceStatus.getProjectId() != projectId) { - removeSessionFromProject(projectPresenceStatus.getProjectId(), userId, sessionId); - } - }); - - /* check access */ - final Project project = projectRepository.findById(projectId).orElseThrow(() -> new NotFoundException("Project not found.")); - projectDAO.checkAccess(message.getUser(), project); - - addSessionToProject(projectId, userId, sessionId); - } catch (IOException e) { - this.webSocketService.sendError(message.getSessionId(), buildError("Received malformed content.", message)); - } catch (UnauthorizedException | NotFoundException e) { - this.webSocketService.sendError(message.getSessionId(), buildError(e.getMessage(), message)); - } finally { - lock.unlock(); - } - } - - public void userLeftProject(WebSocketMessage message) { - lock.lock(); - - try { - final ObjectNode content = (ObjectNode) objectMapper.readTree(message.getContent()); - - final long userId = message.getUser().getId(); - final long projectId = content.get("projectId").asLong(); - final String sessionId = message.getSessionId(); - - removeSessionFromProject(projectId, userId, sessionId); - } catch (IOException e) { - this.webSocketService.sendError(message.getSessionId(), buildError("Received malformed content.", message)); - } catch (UnauthorizedException | NotFoundException e) { - this.webSocketService.sendError(message.getSessionId(), buildError(e.getMessage(), message)); - } finally { - lock.unlock(); - } - } - - private void sessionDisconnect(WebSocketMessage message) { - lock.lock(); - - try { - final long userId = message.getUser().getId(); - final String sessionId = message.getSessionId(); - - Optional.ofNullable(sessionMap.get(sessionId)) - .ifPresent(projectPresenceStatus -> { - removeSessionFromProject(projectPresenceStatus.getProjectId(), userId, sessionId); - }); - } finally { - lock.unlock(); - } - } - - public void statusRequest(WebSocketMessage message) { - lock.lock(); - - try { - final JsonNode projectIds = objectMapper.readTree(message.getContent()).get("projectIds"); - - final WebSocketMessage status = new WebSocketMessage(); - status.setEntity(ProjectPresenceServiceEnum.PROJECT_PRESENCE_SERVICE.name()); - status.setType(ProjectPresenceServiceEnum.STATUS.name()); - - final ObjectNode projects = objectMapper.createObjectNode(); - - projectIds.forEach(projectId -> { - final Project project = projectRepository.findById(projectId.asLong()) - .orElseThrow(() -> new NotFoundException("Project with id " + projectId + " not found.")); - projectDAO.checkAccess(message.getUser(), project); - - projects.set(projectId.asText(), getProjectStatus(projectId.asLong())); - }); - - status.setContent(projects.toString()); - this.webSocketService.sendToSession(message.getSessionId(), status); - } catch (IOException e) { - this.webSocketService.sendError(message.getSessionId(), buildError("Received malformed content.", message)); - } catch (UnauthorizedException | NotFoundException e) { - this.webSocketService.sendError(message.getSessionId(), buildError(e.getMessage(), message)); - } finally { - lock.unlock(); - } - } - - private void addSessionToProject(long projectId, long userId, String sessionId) { - final var projectPresenceStatus = projectPresences.computeIfAbsent(projectId, k -> new ProjectPresenceStatus(projectId)); - - if (projectPresenceStatus.addSession(userId, sessionId)) { - sessionMap.put(sessionId, projectPresenceStatus); - userMap.computeIfAbsent(userId, k -> new HashSet<>()) - .add(projectPresenceStatus); - - broadcastProjectStatus(projectId); - } - } - - private void removeSessionFromProject(long projectId, long userId, String sessionId) { - Optional.ofNullable(projectPresences.get(projectId)) - .ifPresent(projectPresenceStatus -> { - if (projectPresenceStatus.removeSession(userId, sessionId)) { - sessionMap.remove(sessionId); - - if (!projectPresenceStatus.isInUse()) { - projectPresences.remove(projectId); - - userMap.get(userId).remove(projectPresenceStatus); - if (userMap.get(userId).isEmpty()) { - userMap.remove(userId); - } - } - - broadcastProjectStatus(projectId); - } - }); - } - - private void broadcastProjectStatus(long projectId) { - final WebSocketMessage status = new WebSocketMessage(); - status.setEntity(ProjectPresenceServiceEnum.PROJECT_PRESENCE_SERVICE.name()); - status.setType(ProjectPresenceServiceEnum.STATUS.name()); - - final ObjectNode projects = objectMapper.createObjectNode(); - projects.set(Long.toString(projectId), getProjectStatus(projectId)); - status.setContent(projects.toString()); - - this.webSocketService.sendToProjectMembers(projectId, status); - this.webSocketService.sendToProjectOwners(projectId, status); - } - - private ObjectNode getProjectStatus(long projectId) { - final AtomicReference status = new AtomicReference<>(objectMapper.createObjectNode()); - Optional.ofNullable(projectPresences.get(projectId)) - .ifPresent(projectPresenceStatus -> { - status.set(objectMapper.valueToTree(projectPresenceStatus)); - }); - - return status.get(); - } - - public void removeProjectFromPresenceMap(Long projectId) { - lock.lock(); - - try { - Optional.ofNullable(projectPresences.get(projectId)) - .ifPresent(projectPresenceStatus -> { - // remove shortcuts - projectPresenceStatus.userSessions.forEach((userId, sessionIds) -> { - userMap.get(userId).remove(projectPresenceStatus); - if (userMap.get(userId).isEmpty()) { - userMap.remove(userId); - } - sessionIds.forEach(sessionMap::remove); - }); - // remove projectPresenceStatus - projectPresences.remove(projectId); - }); - } finally { - lock.unlock(); - } - } - - public void removeUserFromProjectPresence(Long userId, Long projectId) { - lock.lock(); - - try { - Optional.ofNullable(projectPresences.get(projectId)) - .map(projectPresenceStatus -> projectPresenceStatus.userSessions) - .map(longSetMap -> longSetMap.get(userId)) - .ifPresent(sessionIds -> { - final Set tmp = new HashSet<>(sessionIds); - tmp.forEach(sessionId -> { - projectPresences.get(projectId).removeSession(userId, sessionId); - }); - }); - - broadcastProjectStatus(projectId); - } finally { - lock.unlock(); - } - } - - private WebSocketMessage buildError(String description, WebSocketMessage message) { - final WebSocketMessage error = new WebSocketMessage(); - error.setType(ProjectPresenceServiceEnum.ERROR.name()); - error.setEntity(ProjectPresenceServiceEnum.PROJECT_PRESENCE_SERVICE.name()); - - final ObjectNode errorNode = objectMapper.createObjectNode(); - errorNode.put("description", description); - errorNode.put("message", message.getContent()); - - error.setContent(errorNode.toString()); - - return error; - } - - @PreDestroy - private void cleanUp() { - disposables.forEach(Disposable::dispose); - } - - class ProjectPresenceStatus { - - private final long projectId; - - ProjectPresenceStatus(long projectId) { - this.projectId = projectId; - this.userColors = new HashMap<>(); - this.userSessions = new HashMap<>(); - } - - public long getProjectId() { - return projectId; - } - - @JsonIgnore - Map userColors; - - @JsonIgnore - Map> userSessions; - - public boolean addSession(long userId, String sessionId) { - userSessions.computeIfAbsent(userId, k -> { - userColors.put(userId, nextColor()); - return new HashSet<>(); - }); - - return userSessions.get(userId).add(sessionId); - } - - public boolean removeSession(long userId, String sessionId) { - AtomicBoolean result = new AtomicBoolean(false); - Optional.ofNullable(userSessions.get(userId)) - .ifPresent(sessionSet -> { - if (sessionSet.remove(sessionId)) { - if (sessionSet.isEmpty()) { - userColors.remove(userId); - userSessions.remove(userId); - } - result.set(true); - } - }); - return result.get(); - } - - @JsonIgnore - public boolean isInUse() { - return !userColors.isEmpty(); - } - - @JsonProperty("userColors") - public Map getUserColors() { - return userColors.entrySet().stream() - .collect(Collectors.toMap(k -> userDAO.getByID(k.getKey()).getUsername(), v -> computeRGBColor(v.getValue()))); - } - - private int nextColor() { - Set colorsInUse = new HashSet<>(userColors.values()); - colorsInUse.add(0); - - Set missingColors = IntStream.rangeClosed(Collections.min(colorsInUse), Collections.max(colorsInUse)).boxed() - .collect(Collectors.toSet()); - missingColors.removeAll(colorsInUse); - - return missingColors.stream() - .findFirst() - .orElse(Collections.max(colorsInUse) + 1); - } - - private String computeRGBColor(int colorCode) { - float h = 0.5f; - float goldenRatioA = 0.618033988749895f; - - for (int i = 1; i < colorCode; i++) { - h += goldenRatioA; - h %= 1; - } - - Color color = Color.getHSBColor(h, 0.5f, 0.99f); - String rgbColor = Integer.toHexString(color.getRed()) - + Integer.toHexString(color.getGreen()) - + Integer.toHexString(color.getBlue()); - - return rgbColor.toUpperCase(); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/websocket/services/SymbolPresenceService.java b/backend/src/main/java/de/learnlib/alex/websocket/services/SymbolPresenceService.java deleted file mode 100644 index 984caa6e9..000000000 --- a/backend/src/main/java/de/learnlib/alex/websocket/services/SymbolPresenceService.java +++ /dev/null @@ -1,637 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.websocket.services; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.fasterxml.jackson.annotation.JsonTypeName; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import de.learnlib.alex.auth.dao.UserDAO; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.dao.SymbolDAO; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.SymbolGroup; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.websocket.entities.WebSocketMessage; -import de.learnlib.alex.websocket.services.enums.SymbolPresenceServiceEnum; -import de.learnlib.alex.websocket.services.enums.WebSocketServiceEnum; -import io.reactivex.rxjava3.disposables.Disposable; -import java.io.IOException; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.locks.ReentrantLock; -import java.util.stream.Collectors; -import javax.annotation.PreDestroy; -import org.apache.shiro.authz.UnauthorizedException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -/** - * Service class which tracks user presences in tests. - */ -@Service -@Transactional(rollbackFor = Exception.class) -public class SymbolPresenceService { - - /** - * To ensure non concurrent access over multiple data structures an explicit lock is used. - * This lock is 'fair' in a way that it respects the order of waiting threads when granting access. - */ - private final ReentrantLock lock = new ReentrantLock(true); - - private final ObjectMapper objectMapper; - - private final WebSocketService webSocketService; - - private final SymbolDAO symbolDAO; - - private final ProjectDAO projectDAO; - - private final UserDAO userDAO; - - private final ProjectRepository projectRepository; - - /** A map which stores the SymbolLock objects with the projectId and symbolId as the keys. */ - private final Map> symbolLocks; - - /** A map which stores the SymbolGroupLock objects with the projectId and symbolGroupId as the keys. */ - private final Map> symbolGroupLocks; - - /** Shortcut mapping for easier access given the corresponding sessionId. */ - private final Map sessionMap; - - /** Shortcut mapping for easier access given the corresponding userId. */ - private final Map> userMap; - - private final Set disposables; - - @Autowired - public SymbolPresenceService(WebSocketService webSocketService, - SymbolDAO symbolDAO, - ProjectDAO projectDAO, - UserDAO userDAO, - ProjectRepository projectRepository, - ObjectMapper objectMapper) { - this.webSocketService = webSocketService; - this.symbolDAO = symbolDAO; - this.projectDAO = projectDAO; - this.userDAO = userDAO; - this.projectRepository = projectRepository; - this.objectMapper = objectMapper; - - this.disposables = new HashSet<>(); - this.symbolLocks = new HashMap<>(); - this.symbolGroupLocks = new HashMap<>(); - this.sessionMap = new HashMap<>(); - this.userMap = new HashMap<>(); - - disposables.add( - this.webSocketService.register( - message -> message.getEntity().equals(SymbolPresenceServiceEnum.SYMBOL_PRESENCE_SERVICE.name()) - && message.getType().equals(SymbolPresenceServiceEnum.USER_ENTERED.name())) - .subscribe(this::userEnteredSymbol) - ); - disposables.add( - this.webSocketService.register( - message -> message.getEntity().equals(SymbolPresenceServiceEnum.SYMBOL_PRESENCE_SERVICE.name()) - && message.getType().equals(SymbolPresenceServiceEnum.USER_LEFT.name())) - .subscribe(this::userLeftSymbol) - ); - disposables.add( - this.webSocketService.register( - message -> message.getEntity().equals(SymbolPresenceServiceEnum.SYMBOL_PRESENCE_SERVICE.name()) - && message.getType().equals(SymbolPresenceServiceEnum.STATUS_REQUEST.name())) - .subscribe(this::statusRequest) - ); - disposables.add( - this.webSocketService.register( - message -> message.getEntity().equals(WebSocketServiceEnum.WEBSOCKET_SERVICE_INTERNAL.name()) - && message.getType().equals(WebSocketServiceEnum.SESSION_DISCONNECT.name())) - .subscribe(this::sessionDisconnect) - ); - } - - public void userEnteredSymbol(WebSocketMessage message) { - lock.lock(); - - try { - final ObjectNode content = (ObjectNode) objectMapper.readTree(message.getContent()); - - final long userId = message.getUser().getId(); - final long projectId = content.get("projectId").asLong(); - final long symbolId = content.get("symbolId").asLong(); - final String sessionId = message.getSessionId(); - - /* session already acquired another symbolLock */ - Optional.ofNullable(sessionMap.get(sessionId)) - .ifPresent(symbolLock -> { - if (symbolLock.getSymbolId() != symbolId) { - releaseSymbolLock(symbolLock.getProjectId(), symbolLock.getSymbolId(), userId, sessionId); - } - }); - - /* check access */ - final Project project = projectRepository.findById(projectId) - .orElseThrow(() -> new NotFoundException("Project with id " + projectId + " not found.")); - projectDAO.checkAccess(message.getUser(), project); - - acquireSymbolLock(projectId, symbolId, userId, sessionId); - - } catch (IOException e) { - this.webSocketService.sendError(message.getSessionId(), buildError("Received malformed content.", message)); - } catch (UnauthorizedException | NotFoundException e) { - this.webSocketService.sendError(message.getSessionId(), buildError(e.getMessage(), message)); - } finally { - lock.unlock(); - } - } - - public void userLeftSymbol(WebSocketMessage message) { - lock.lock(); - - try { - ObjectNode content = (ObjectNode) objectMapper.readTree(message.getContent()); - - final long userId = message.getUser().getId(); - final long projectId = content.get("projectId").asLong(); - final long symbolId = content.get("symbolId").asLong(); - final String sessionId = message.getSessionId(); - - releaseSymbolLock(projectId, symbolId, userId, sessionId); - - } catch (IOException e) { - this.webSocketService.sendError(message.getSessionId(), buildError("Received malformed content.", message)); - } catch (UnauthorizedException | NotFoundException e) { - this.webSocketService.sendError(message.getSessionId(), buildError(e.getMessage(), message)); - } finally { - lock.unlock(); - } - } - - public void sessionDisconnect(WebSocketMessage message) { - lock.lock(); - - try { - final long userId = message.getUser().getId(); - final String sessionId = message.getSessionId(); - - Optional.ofNullable(sessionMap.get(sessionId)) - .ifPresent(symbolLock -> { - releaseSymbolLock(symbolLock.getProjectId(), symbolLock.getSymbolId(), userId, sessionId); - }); - - } finally { - lock.unlock(); - } - } - - public void statusRequest(WebSocketMessage message) { - lock.lock(); - - try { - final JsonNode projectIds = objectMapper.readTree(message.getContent()).get("projectIds"); - - final WebSocketMessage status = new WebSocketMessage(); - status.setEntity(SymbolPresenceServiceEnum.SYMBOL_PRESENCE_SERVICE.name()); - status.setType(SymbolPresenceServiceEnum.STATUS.name()); - - final ObjectNode projects = objectMapper.createObjectNode(); - - projectIds.forEach(projectId -> { - final Project project = projectRepository.findById(projectId.asLong()) - .orElseThrow(() -> new NotFoundException("Project with id " + projectId + " not found.")); - projectDAO.checkAccess(message.getUser(), project); - - projects.set(projectId.asText(), getProjectStatus(projectId.asLong())); - }); - - status.setContent(projects.toString()); - this.webSocketService.sendToSession(message.getSessionId(), status); - } catch (IOException e) { - this.webSocketService.sendError(message.getSessionId(), buildError("Received malformed content.", message)); - } catch (UnauthorizedException | NotFoundException e) { - this.webSocketService.sendError(message.getSessionId(), buildError(e.getMessage(), message)); - } finally { - lock.unlock(); - } - } - - public void checkSymbolLockStatus(long projectId, long symbolId, long userId) { - lock.lock(); - - try { - Optional.ofNullable(symbolLocks.get(projectId)) - .map(projectMap -> projectMap.get(symbolId)) - .ifPresent(symbolLock -> { - if (symbolLock.lockOwner != userId) { - throw new UnauthorizedException("This symbol is currently locked."); - } - }); - } finally { - lock.unlock(); - } - } - - public void checkSymbolLockStatusStrict(long projectId, long symbolId, long userId) { - lock.lock(); - - try { - Optional.ofNullable(symbolLocks.get(projectId)) - .map(projectMap -> projectMap.get(symbolId)) - .ifPresent(symbolLock -> { - throw new UnauthorizedException("This symbol is currently locked."); - }); - } finally { - lock.unlock(); - } - } - - public void checkGroupLockStatus(long projectId, long groupId) { - lock.lock(); - - try { - Optional.ofNullable(symbolLocks.get(projectId)) - .map(projectMap -> projectMap.get(groupId)) - .ifPresent(l -> { - throw new UnauthorizedException("This symbolgroup is currently locked."); - }); - } finally { - lock.unlock(); - } - } - - public void releaseUserLocksFromProject(long userId, long projectId) { - lock.lock(); - - try { - Optional.ofNullable(userMap.get(userId)) - .map(userSymbolLocks -> userSymbolLocks.stream() - .filter(symbolLock -> symbolLock.getProjectId() == projectId) - .collect(Collectors.toSet()) - ) - .ifPresent(userSymbolLocks -> { - userSymbolLocks.forEach(symbolLock -> { - final Set tmp = new HashSet<>(symbolLock.lockSessions); - tmp.forEach(symbolLock::removeSession); - }); - }); - } finally { - lock.unlock(); - } - } - - public void releaseSymbolLocksByUser(long userId) { - lock.lock(); - - try { - Optional.ofNullable(userMap.get(userId)) - .ifPresent(symbolLocks -> { - final Set tmpSymbolLocks = new HashSet<>(symbolLocks); - tmpSymbolLocks.forEach(symbolLock -> { - final Set tmpSessionSet = new HashSet<>(symbolLock.lockSessions); - tmpSessionSet.forEach(sessionId -> { - releaseSymbolLock(symbolLock.getProjectId(), symbolLock.getSymbolId(), userId, sessionId); - }); - }); - }); - } finally { - lock.unlock(); - } - } - - public void releaseSymbolLocksByProject(long projectId) { - lock.lock(); - - try { - final AtomicReference it = new AtomicReference<>(sessionMap.entrySet().iterator()); - while (it.get().hasNext()) { - final Map.Entry e = (Map.Entry) it.get().next(); - if (((SymbolLock) e.getValue()).getProjectId() == projectId) { - it.get().remove(); - } - } - - userMap.forEach((userId, symbolLocks) -> { - it.set(symbolLocks.iterator()); - while (it.get().hasNext()) { - SymbolLock l = (SymbolLock) it.get().next(); - if (l.getProjectId() == projectId) { - it.get().remove(); - } - } - }); - - it.set(userMap.entrySet().iterator()); - while (it.get().hasNext()) { - final Map.Entry e = (Map.Entry) it.get().next(); - if (((HashSet) e.getValue()).isEmpty()) { - it.get().remove(); - } - } - - symbolLocks.remove(projectId); - symbolGroupLocks.remove(projectId); - - } finally { - lock.unlock(); - } - } - - private void acquireSymbolLock(long projectId, long symbolId, long userId, String sessionId) { - SymbolLock symbolLock = symbolLocks.computeIfAbsent(projectId, k -> new HashMap<>()) - .computeIfAbsent(symbolId, k -> new SymbolLock(projectId, symbolId)); - - if (symbolLock.addSession(userId, sessionId)) { - sessionMap.put(sessionId, symbolLock); - userMap.computeIfAbsent(userId, k -> new HashSet<>()) - .add(symbolLock); - - SymbolGroup symbolGroup = symbolDAO.get(userDAO.getByID(userId), projectId, symbolId).getGroup(); - while (symbolGroup != null) { - symbolGroupLocks.computeIfAbsent(projectId, k -> new HashMap<>()) - .computeIfAbsent(symbolGroup.getId(), k -> new SymbolGroupLock(projectId, k)) - .addSession(userId, sessionId); - - symbolGroup = symbolGroup.getParent(); - } - broadcastSymbolStatus(projectId); - } - } - - private void releaseSymbolLock(long projectId, long symbolId, long userId, String sessionId) { - Optional.ofNullable(symbolLocks.get(projectId)) - .map(m -> m.get(symbolId)) - .ifPresent(symbolLock -> { - if (symbolLock.removeSession(sessionId)) { - sessionMap.remove(sessionId); - - if (!symbolLock.isLocked()) { - symbolLocks.get(projectId).remove(symbolId); - - userMap.get(userId).remove(symbolLock); - if (userMap.get(userId).isEmpty()) { - userMap.remove(userId); - } - } - - SymbolGroup symbolGroup = symbolDAO.get(userDAO.getByID(userId), projectId, symbolId).getGroup(); - while (symbolGroup != null) { - - final SymbolGroupLock symbolGroupLock = symbolGroupLocks.get(projectId).get(symbolGroup.getId()); - symbolGroupLock.removeSession(userId, sessionId); - - if (!symbolGroupLock.isLocked()) { - symbolGroupLocks.get(projectId).remove(symbolGroupLock.getSymbolGroupId()); - } - - symbolGroup = symbolGroup.getParent(); - - } - - if (symbolLocks.get(projectId).isEmpty()) { - symbolLocks.remove(projectId); - } - - if (symbolGroupLocks.get(projectId).isEmpty()) { - symbolGroupLocks.remove(projectId); - } - broadcastSymbolStatus(projectId); - } - }); - } - - private ObjectNode getProjectStatus(long projectId) { - final ObjectNode status = objectMapper.createObjectNode(); - final ObjectNode symbolsNode = objectMapper.createObjectNode(); - final ObjectNode symbolGroupsNode = objectMapper.createObjectNode(); - - Optional.ofNullable(symbolLocks.get(projectId)) - .ifPresent(m -> { - m.forEach((symbolId, symbolLock) -> { - symbolsNode.set(Long.toString(symbolId), objectMapper.valueToTree(symbolLock)); - }); - }); - Optional.ofNullable(symbolGroupLocks.get(projectId)) - .ifPresent(m -> { - m.forEach((symbolGroupId, symbolGroupLock) -> { - symbolGroupsNode.set(Long.toString(symbolGroupId), objectMapper.valueToTree(symbolGroupLock)); - }); - }); - status.set("symbols", symbolsNode); - status.set("groups", symbolGroupsNode); - - return status; - } - - private void broadcastSymbolStatus(long projectId) { - final WebSocketMessage status = new WebSocketMessage(); - status.setEntity(SymbolPresenceServiceEnum.SYMBOL_PRESENCE_SERVICE.name()); - status.setType(SymbolPresenceServiceEnum.STATUS.name()); - - final ObjectNode projects = objectMapper.createObjectNode(); - projects.set(Long.toString(projectId), getProjectStatus(projectId)); - status.setContent(projects.toString()); - - this.webSocketService.sendToProjectMembers(projectId, status); - this.webSocketService.sendToProjectOwners(projectId, status); - } - - private WebSocketMessage buildError(String description, WebSocketMessage message) { - final WebSocketMessage error = new WebSocketMessage(); - error.setType(SymbolPresenceServiceEnum.ERROR.name()); - error.setEntity(SymbolPresenceServiceEnum.SYMBOL_PRESENCE_SERVICE.name()); - - final ObjectNode errorNode = objectMapper.createObjectNode(); - errorNode.put("description", description); - errorNode.put("message", message.getContent()); - - error.setContent(errorNode.toString()); - - return error; - } - - @PreDestroy - private void cleanUp() { - disposables.forEach(Disposable::dispose); - } - - @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") - @JsonSubTypes({ - @JsonSubTypes.Type(name = "symbol", value = SymbolLock.class), - @JsonSubTypes.Type(name = "group", value = SymbolGroupLock.class), - }) - abstract class AbstractSymbolLock { - - private final long projectId; - - AbstractSymbolLock(long projectId) { - this.projectId = projectId; - } - - public long getProjectId() { - return projectId; - } - } - - @JsonTypeName("symbol") - class SymbolLock extends AbstractSymbolLock { - - private final long symbolId; - - @JsonIgnore - private long lockOwner; - - @JsonIgnore - private final Set lockSessions; - - @JsonIgnore - private final Map timestamps; - - SymbolLock(long projectId, long symbolId) { - super(projectId); - this.symbolId = symbolId; - - this.lockSessions = new HashSet<>(); - this.timestamps = new HashMap<>(); - } - - public long getLockOwner() { - return lockOwner; - } - - public long getSymbolId() { - return symbolId; - } - - public boolean addSession(long userId, String sessionId) { - if (lockSessions.isEmpty()) { - lockOwner = userId; - } else if (lockOwner != userId) { - throw new UnauthorizedException("Symbol is already locked."); - } - if (lockSessions.add(sessionId)) { - timestamps.put(sessionId, new Date()); - return true; - } - return false; - } - - public boolean removeSession(String sessionId) { - if (lockSessions.remove(sessionId)) { - timestamps.remove(sessionId); - - if (lockSessions.isEmpty()) { - lockOwner = -1; - } - return true; - } - return false; - } - - @JsonIgnore - public boolean isLocked() { - return lockOwner != -1; - } - - @JsonProperty("username") - public String getUsername() { - return userDAO.getByID(lockOwner).getUsername(); - } - - @JsonProperty("timestamp") - public long getOldestTimestampMillis() { - return timestamps.values().stream().min(Date::compareTo).get().getTime(); - } - } - - @JsonTypeName("group") - class SymbolGroupLock extends AbstractSymbolLock { - - private final long symbolGroupId; - - @JsonIgnore - private final Set lockOwners; - - @JsonIgnore - private final Map> lockSessions; - - SymbolGroupLock(long projectId, long symbolId) { - super(projectId); - this.symbolGroupId = symbolId; - - this.lockOwners = new HashSet<>(); - this.lockSessions = new HashMap<>(); - } - - public Set getLockOwners() { - return lockOwners; - } - - public long getSymbolGroupId() { - return symbolGroupId; - } - - public boolean addSession(long userId, String sessionId) { - lockSessions.computeIfAbsent(userId, k -> { - lockOwners.add(userId); - return new HashSet<>(); - }); - - return lockSessions.get(userId).add(sessionId); - } - - public boolean removeSession(long userId, String sessionId) { - AtomicBoolean result = new AtomicBoolean(false); - Optional.ofNullable(lockSessions.get(userId)) - .ifPresent(sessionSet -> { - if (sessionSet.remove(sessionId)) { - if (sessionSet.isEmpty()) { - lockOwners.remove(userId); - lockSessions.remove(userId); - } - result.set(true); - } - }); - - return result.get(); - } - - @JsonIgnore - public boolean isLocked() { - return !lockOwners.isEmpty(); - } - - @JsonProperty("locks") - public List getLockOwnersNames() { - return lockOwners.stream().map(userId -> userDAO.getByID(userId).getUsername()).collect(Collectors.toList()); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/websocket/services/TestPresenceService.java b/backend/src/main/java/de/learnlib/alex/websocket/services/TestPresenceService.java deleted file mode 100644 index 0fd1c4a31..000000000 --- a/backend/src/main/java/de/learnlib/alex/websocket/services/TestPresenceService.java +++ /dev/null @@ -1,604 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.websocket.services; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.fasterxml.jackson.annotation.JsonTypeName; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import de.learnlib.alex.auth.dao.UserDAO; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.testing.dao.TestDAO; -import de.learnlib.alex.testing.entities.Test; -import de.learnlib.alex.testing.entities.TestCase; -import de.learnlib.alex.websocket.entities.WebSocketMessage; -import de.learnlib.alex.websocket.services.enums.TestPresenceServiceEnum; -import de.learnlib.alex.websocket.services.enums.WebSocketServiceEnum; -import io.reactivex.rxjava3.disposables.Disposable; -import java.io.IOException; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.locks.ReentrantLock; -import java.util.stream.Collectors; -import javax.annotation.PreDestroy; -import org.apache.shiro.authz.UnauthorizedException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -/** - * Service class which tracks user presences in tests. - */ -@Service -@Transactional(rollbackFor = Exception.class) -public class TestPresenceService { - - /** - * To ensure non concurrent access over multiple data structures an explicit lock is used. - * This lock is 'fair' in a way that it respects the order of waiting threads when granting access. - */ - private final ReentrantLock lock = new ReentrantLock(true); - - private final ObjectMapper objectMapper; - - private final WebSocketService webSocketService; - - private final TestDAO testDAO; - - private final ProjectDAO projectDAO; - - private final UserDAO userDAO; - - private final ProjectRepository projectRepository; - - /** A map which stores the TestLock objects with the projectId and testId as the keys. */ - private final Map> testLocks; - - /** Shortcut mapping for easier access given the corresponding sessionId. */ - private final Map sessionMap; - - /** Shortcut mapping for easier access given the corresponding userId. */ - private final Map> userMap; - - private final Set disposables; - - @Autowired - public TestPresenceService(WebSocketService webSocketService, - TestDAO testDAO, - ProjectDAO projectDAO, - UserDAO userDAO, - ProjectRepository projectRepository, - ObjectMapper objectMapper) { - this.webSocketService = webSocketService; - this.testDAO = testDAO; - this.projectDAO = projectDAO; - this.userDAO = userDAO; - this.projectRepository = projectRepository; - this.objectMapper = objectMapper; - - - this.disposables = new HashSet<>(); - this.testLocks = new HashMap<>(); - this.sessionMap = new HashMap<>(); - this.userMap = new HashMap<>(); - - disposables.add( - this.webSocketService.register( - message -> message.getEntity().equals(TestPresenceServiceEnum.TEST_PRESENCE_SERVICE.name()) - && message.getType().equals(TestPresenceServiceEnum.USER_ENTERED.name())) - .subscribe(this::userEnteredTest) - ); - disposables.add( - this.webSocketService.register( - message -> message.getEntity().equals(TestPresenceServiceEnum.TEST_PRESENCE_SERVICE.name()) - && message.getType().equals(TestPresenceServiceEnum.USER_LEFT.name())) - .subscribe(this::userLeftTest) - ); - disposables.add( - this.webSocketService.register( - message -> message.getEntity().equals(TestPresenceServiceEnum.TEST_PRESENCE_SERVICE.name()) - && message.getType().equals(TestPresenceServiceEnum.STATUS_REQUEST.name())) - .subscribe(this::statusRequest) - ); - disposables.add( - this.webSocketService.register( - message -> message.getEntity().equals(WebSocketServiceEnum.WEBSOCKET_SERVICE_INTERNAL.name()) - && message.getType().equals(WebSocketServiceEnum.SESSION_DISCONNECT.name())) - .subscribe(this::sessionDisconnect) - ); - } - - - public void userEnteredTest(WebSocketMessage message) { - lock.lock(); - - try { - final ObjectNode content = (ObjectNode) objectMapper.readTree(message.getContent()); - - final long userId = message.getUser().getId(); - final long projectId = content.get("projectId").asLong(); - final long testId = content.get("testId").asLong(); - final String sessionId = message.getSessionId(); - - /* session already acquired another testLock */ - Optional.ofNullable(sessionMap.get(sessionId)) - .ifPresent(testLock -> { - if (testLock.getTestId() != testId) { - releaseTestLock(testLock.getProjectId(), testLock.getTestId(), userId, sessionId); - } - }); - - /* check access */ - final Project project = projectRepository.findById(projectId) - .orElseThrow(() -> new NotFoundException("Project with id " + projectId + " not found.")); - projectDAO.checkAccess(message.getUser(), project); - - /* ignore TestSuites */ - if (testDAO.get(userDAO.getByID(userId), projectId, testId) instanceof TestCase) { - acquireTestLock(projectId, testId, userId, sessionId); - } - - } catch (IOException e) { - this.webSocketService.sendError(message.getSessionId(), buildError("Received malformed content.", message)); - } catch (UnauthorizedException | NotFoundException e) { - this.webSocketService.sendError(message.getSessionId(), buildError(e.getMessage(), message)); - } finally { - lock.unlock(); - } - } - - public void userLeftTest(WebSocketMessage message) { - lock.lock(); - - try { - final ObjectNode content = (ObjectNode) objectMapper.readTree(message.getContent()); - - final long userId = message.getUser().getId(); - final long projectId = content.get("projectId").asLong(); - final long testId = content.get("testId").asLong(); - final String sessionId = message.getSessionId(); - - /* Ignore TestSuites */ - if (testDAO.get(userDAO.getByID(userId), projectId, testId) instanceof TestCase) { - releaseTestLock(projectId, testId, userId, sessionId); - } - - } catch (IOException e) { - this.webSocketService.sendError(message.getSessionId(), buildError("Received malformed content.", message)); - } catch (UnauthorizedException | NotFoundException e) { - this.webSocketService.sendError(message.getSessionId(), buildError(e.getMessage(), message)); - } finally { - lock.unlock(); - } - } - - public void sessionDisconnect(WebSocketMessage message) { - lock.lock(); - - try { - final long userId = message.getUser().getId(); - final String sessionId = message.getSessionId(); - - Optional.ofNullable(sessionMap.get(sessionId)) - .ifPresent(testCaseLock -> { - releaseTestLock(testCaseLock.getProjectId(), testCaseLock.getTestId(), userId, sessionId); - }); - - } finally { - lock.unlock(); - } - } - - public void statusRequest(WebSocketMessage message) { - lock.lock(); - - try { - final JsonNode projectIds = objectMapper.readTree(message.getContent()).get("projectIds"); - - final WebSocketMessage status = new WebSocketMessage(); - status.setEntity(TestPresenceServiceEnum.TEST_PRESENCE_SERVICE.name()); - status.setType(TestPresenceServiceEnum.STATUS.name()); - - final ObjectNode projects = objectMapper.createObjectNode(); - - projectIds.forEach(projectId -> { - final Project project = projectRepository.findById(projectId.asLong()) - .orElseThrow(() -> new NotFoundException("Project with id " + projectId + " not found.")); - projectDAO.checkAccess(message.getUser(), project); - - projects.set(projectId.asText(), getProjectStatus(projectId.asLong())); - }); - - status.setContent(projects.toString()); - this.webSocketService.sendToSession(message.getSessionId(), status); - } catch (IOException e) { - this.webSocketService.sendError(message.getSessionId(), buildError("Received malformed content.", message)); - } catch (UnauthorizedException | NotFoundException e) { - this.webSocketService.sendError(message.getSessionId(), buildError(e.getMessage(), message)); - } finally { - lock.unlock(); - } - } - - public void checkLockStatus(long projectId, long testId, long userId) throws UnauthorizedException { - lock.lock(); - - try { - Optional.ofNullable(testLocks.get(projectId)) - .map(projectMap -> projectMap.get(testId)) - .ifPresent(testLock -> { - if ((testLock instanceof TestSuiteLock) || ((TestCaseLock) testLock).lockOwner != userId) { - throw new UnauthorizedException("This test is currently locked."); - } - }); - } finally { - lock.unlock(); - } - } - - public void checkLockStatusStrict(long projectId, long testId, long userId) throws UnauthorizedException { - lock.lock(); - - try { - Optional.ofNullable(testLocks.get(projectId)) - .map(projectMap -> projectMap.get(testId)) - .ifPresent(testLock -> { - throw new UnauthorizedException("This test is currently locked."); - }); - } finally { - lock.unlock(); - } - } - - public void releaseUserLocksFromProject(long userId, long projectId) { - lock.lock(); - - try { - Optional.ofNullable(userMap.get(userId)) - .map(testCaseLocks -> testCaseLocks.stream() - .filter(testCaseLock -> testCaseLock.getProjectId() == projectId) - .collect(Collectors.toSet()) - ) - .ifPresent(testCaseLocks -> { - testCaseLocks.forEach(testCaseLock -> { - final Set tmp = new HashSet<>(testCaseLock.lockSessions); - tmp.forEach(testCaseLock::removeSession); - }); - }); - } finally { - lock.unlock(); - } - } - - public void releaseTestLocksByUser(long userId) { - lock.lock(); - - try { - Optional.ofNullable(userMap.get(userId)) - .ifPresent(testCaseLocks -> { - final Set tmpTestCaseLocks = new HashSet<>(testCaseLocks); - tmpTestCaseLocks.forEach(testCaseLock -> { - final Set tmpSessionSet = new HashSet<>(testCaseLock.lockSessions); - tmpSessionSet.forEach(sessionId -> { - releaseTestLock(testCaseLock.getProjectId(), testCaseLock.getTestId(), userId, sessionId); - }); - }); - }); - } finally { - lock.unlock(); - } - } - - public void releaseTestLocksByProject(long projectId) { - lock.lock(); - - try { - final AtomicReference it = new AtomicReference<>(sessionMap.entrySet().iterator()); - while (it.get().hasNext()) { - final Map.Entry e = (Map.Entry) it.get().next(); - if (((TestCaseLock) e.getValue()).getProjectId() == projectId) { - it.get().remove(); - } - } - - userMap.forEach((userId, testCaseLocks) -> { - it.set(testCaseLocks.iterator()); - while (it.get().hasNext()) { - final TestCaseLock l = (TestCaseLock) it.get().next(); - if (l.getProjectId() == projectId) { - it.get().remove(); - } - } - }); - - it.set(userMap.entrySet().iterator()); - while (it.get().hasNext()) { - final Map.Entry e = (Map.Entry) it.get().next(); - if (((HashSet) e.getValue()).isEmpty()) { - it.get().remove(); - } - } - - testLocks.remove(projectId); - - } finally { - lock.unlock(); - } - } - - private void acquireTestLock(long projectId, long testId, long userId, String sessionId) { - final TestCaseLock testCaseLock = (TestCaseLock) testLocks.computeIfAbsent(projectId, k -> new HashMap<>()) - .computeIfAbsent(testId, k -> new TestCaseLock(projectId, testId)); - - if (testCaseLock.addSession(userId, sessionId)) { - sessionMap.put(sessionId, testCaseLock); - userMap.computeIfAbsent(userId, k -> new HashSet<>()) - .add(testCaseLock); - - Test test = testDAO.get(userDAO.getByID(userId), projectId, testId); - while (test.getParent() != null) { - test = test.getParent(); - - ((TestSuiteLock) testLocks.get(projectId).computeIfAbsent(test.getId(), k -> new TestSuiteLock(projectId, k))) - .addSession(userId, sessionId); - } - broadcastTestStatus(projectId); - } - } - - private void releaseTestLock(long projectId, long testId, long userId, String sessionId) { - Optional.ofNullable(testLocks.get(projectId)) - .map(m -> m.get(testId)) - .ifPresent(testCaseLock -> { - if (((TestCaseLock) testCaseLock).removeSession(sessionId)) { - sessionMap.remove(sessionId); - - if (!((TestCaseLock) testCaseLock).isLocked()) { - testLocks.get(projectId).remove(testId); - - userMap.get(userId).remove(testCaseLock); - if (userMap.get(userId).isEmpty()) { - userMap.remove(userId); - } - } - - Test test = testDAO.get(userDAO.getByID(userId), projectId, testId); - while (test.getParent() != null) { - - test = test.getParent(); - - final TestSuiteLock testSuiteLock = (TestSuiteLock) testLocks.get(projectId).get(test.getId()); - testSuiteLock.removeSession(userId, sessionId); - - if (!testSuiteLock.isLocked()) { - testLocks.get(projectId).remove(testSuiteLock.getTestId()); - } - } - - if (testLocks.get(projectId).isEmpty()) { - testLocks.remove(projectId); - } - broadcastTestStatus(projectId); - } - }); - } - - private ObjectNode getProjectStatus(long projectId) { - final ObjectNode tests = objectMapper.createObjectNode(); - - Optional.ofNullable(testLocks.get(projectId)) - .ifPresent(m -> { - m.forEach((testId, testLock) -> { - tests.set(Long.toString(testId), objectMapper.valueToTree(testLock)); - }); - }); - - return tests; - } - - private void broadcastTestStatus(long projectId) { - final WebSocketMessage status = new WebSocketMessage(); - status.setEntity(TestPresenceServiceEnum.TEST_PRESENCE_SERVICE.name()); - status.setType(TestPresenceServiceEnum.STATUS.name()); - - final ObjectNode projects = objectMapper.createObjectNode(); - projects.set(Long.toString(projectId), getProjectStatus(projectId)); - status.setContent(projects.toString()); - - this.webSocketService.sendToProjectMembers(projectId, status); - this.webSocketService.sendToProjectOwners(projectId, status); - } - - private WebSocketMessage buildError(String description, WebSocketMessage message) { - final WebSocketMessage error = new WebSocketMessage(); - error.setType(TestPresenceServiceEnum.ERROR.name()); - error.setEntity(TestPresenceServiceEnum.TEST_PRESENCE_SERVICE.name()); - - final ObjectNode errorNode = objectMapper.createObjectNode(); - errorNode.put("description", description); - errorNode.put("message", message.getContent()); - - error.setContent(errorNode.toString()); - - return error; - } - - @PreDestroy - private void cleanUp() { - disposables.forEach(Disposable::dispose); - } - - @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") - @JsonSubTypes({ - @JsonSubTypes.Type(name = "case", value = TestCaseLock.class), - @JsonSubTypes.Type(name = "suite", value = TestSuiteLock.class), - }) - abstract class TestLock { - - private final long testId; - private final long projectId; - - TestLock(long projectId, long testId) { - this.projectId = projectId; - this.testId = testId; - } - - public long getProjectId() { - return projectId; - } - - public long getTestId() { - return testId; - } - } - - @JsonTypeName("case") - class TestCaseLock extends TestLock { - - @JsonIgnore - private long lockOwner; - - @JsonIgnore - private final Set lockSessions; - - @JsonIgnore - private final Map timestamps; - - TestCaseLock(long projectId, long testId) { - super(projectId, testId); - - this.lockSessions = new HashSet<>(); - this.timestamps = new HashMap<>(); - } - - public long getLockOwner() { - return lockOwner; - } - - public boolean addSession(long userId, String sessionId) { - if (lockSessions.isEmpty()) { - lockOwner = userId; - } else if (lockOwner != userId) { - throw new UnauthorizedException("Test is already locked."); - } - if (lockSessions.add(sessionId)) { - timestamps.put(sessionId, new Date()); - return true; - } - return false; - } - - public boolean removeSession(String sessionId) { - if (lockSessions.remove(sessionId)) { - timestamps.remove(sessionId); - - if (lockSessions.isEmpty()) { - lockOwner = -1; - } - return true; - } - return false; - } - - @JsonIgnore - public boolean isLocked() { - return lockOwner != -1; - } - - @JsonProperty("username") - public String getUsername() { - return userDAO.getByID(lockOwner).getUsername(); - } - - @JsonProperty("timestamp") - public long getOldestTimestampMillis() { - return timestamps.values().stream().min(Date::compareTo).get().getTime(); - } - } - - @JsonTypeName("suite") - class TestSuiteLock extends TestLock { - - @JsonIgnore - Set lockOwners; - - @JsonIgnore - Map> lockSessions; - - TestSuiteLock(long projectId, long testId) { - super(projectId, testId); - this.lockOwners = new HashSet<>(); - this.lockSessions = new HashMap<>(); - } - - public Set getLockOwners() { - return lockOwners; - } - - public boolean addSession(long userId, String sessionId) { - lockSessions.computeIfAbsent(userId, k -> { - lockOwners.add(userId); - return new HashSet<>(); - }); - - return lockSessions.get(userId).add(sessionId); - } - - public boolean removeSession(long userId, String sessionId) { - AtomicBoolean result = new AtomicBoolean(false); - Optional.ofNullable(lockSessions.get(userId)) - .ifPresent(sessionSet -> { - if (sessionSet.remove(sessionId)) { - if (sessionSet.isEmpty()) { - lockOwners.remove(userId); - lockSessions.remove(userId); - } - result.set(true); - } - }); - - return result.get(); - } - - @JsonIgnore - public boolean isLocked() { - return !lockOwners.isEmpty(); - } - - @JsonProperty("locks") - public List getLockOwnersNames() { - return lockOwners.stream() - .map(userId -> userDAO.getByID(userId).getUsername()) - .collect(Collectors.toList()); - } - } -} diff --git a/backend/src/main/java/de/learnlib/alex/websocket/services/WebSocketService.java b/backend/src/main/java/de/learnlib/alex/websocket/services/WebSocketService.java deleted file mode 100644 index 54d0197ca..000000000 --- a/backend/src/main/java/de/learnlib/alex/websocket/services/WebSocketService.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.websocket.services; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.websocket.entities.WebSocketMessage; -import de.learnlib.alex.websocket.services.enums.WebSocketServiceEnum; -import io.reactivex.rxjava3.subjects.PublishSubject; -import java.io.IOException; -import java.security.Principal; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Predicate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.event.EventListener; -import org.springframework.messaging.simp.SimpAttributesContextHolder; -import org.springframework.messaging.simp.SimpMessageHeaderAccessor; -import org.springframework.messaging.simp.SimpMessageType; -import org.springframework.messaging.simp.SimpMessagingTemplate; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.socket.WebSocketSession; -import org.springframework.web.socket.messaging.SessionConnectEvent; -import org.springframework.web.socket.messaging.SessionDisconnectEvent; - -@Service -@Transactional(rollbackFor = Exception.class) -public class WebSocketService { - - private final ReentrantLock lock = new ReentrantLock(true); - - private final ProjectRepository projectRepository; - - private final SimpMessagingTemplate simpMessagingTemplate; - - private final ObjectMapper objectMapper; - - private final Map, PublishSubject> serviceSubjects; - - /* userId -> WebSocketSessions Username */ - private final Map activeUsers; - - /* Stores the sessionIds of active connections per user */ - private final Map> userSessionIds; - - /* sessionId -> WebSocketSession */ - private final Map webSocketSessions; - - @Autowired - public WebSocketService(SimpMessagingTemplate simpMessagingTemplate, - ProjectRepository projectRepository, - ObjectMapper objectMapper) { - this.simpMessagingTemplate = simpMessagingTemplate; - this.projectRepository = projectRepository; - this.objectMapper = objectMapper; - - this.activeUsers = new HashMap<>(); - this.userSessionIds = new HashMap<>(); - this.serviceSubjects = new HashMap<>(); - this.webSocketSessions = new HashMap<>(); - } - - public void processIncomingMessage(WebSocketMessage msg, Principal userPrincipal) { - lock.lock(); - - try { - msg.setUser((User) ((UsernamePasswordAuthenticationToken) userPrincipal).getPrincipal()); - msg.setSessionId(SimpAttributesContextHolder.currentAttributes().getSessionId()); - - if (msg.getEntity().equals(WebSocketServiceEnum.WEBSOCKET_SERVICE.name()) - && msg.getType().equals(WebSocketServiceEnum.LOGOUT.name())) { - final WebSocketMessage message = new WebSocketMessage(); - message.setEntity(WebSocketServiceEnum.WEBSOCKET_SERVICE.name()); - message.setType(WebSocketServiceEnum.LOGOUT_CHECK.name()); - - this.sendToUser(msg.getUser().getId(), message); - closeSession(msg.getSessionId()); - } - - if (msg.getEntity().equals(WebSocketServiceEnum.WEBSOCKET_SERVICE.name()) - && msg.getType().equals(WebSocketServiceEnum.REQUEST_SESSION_ID.name())) { - final WebSocketMessage message = new WebSocketMessage(); - message.setEntity(WebSocketServiceEnum.WEBSOCKET_SERVICE.name()); - message.setType(WebSocketServiceEnum.SESSION_ID.name()); - - final ObjectNode content = objectMapper.createObjectNode(); - content.put("sessionId", msg.getSessionId()); - message.setContent(content.toString()); - - this.sendToSession(msg.getSessionId(), message); - } - - if (!msg.getEntity().equals(WebSocketServiceEnum.WEBSOCKET_SERVICE_INTERNAL.name())) { - publishMessage(msg); - } else { - final WebSocketMessage message = new WebSocketMessage(); - message.setEntity(WebSocketServiceEnum.WEBSOCKET_SERVICE.name()); - message.setType(WebSocketServiceEnum.ERROR.name()); - - final ObjectNode content = objectMapper.createObjectNode(); - content.put("description", "Received system reserved entity type."); - content.put("message", objectMapper.writeValueAsString(msg)); - message.setContent(content.toString()); - - this.sendError(msg.getSessionId(), message); - } - } catch (JsonProcessingException e) { - //Ignore - } finally { - lock.unlock(); - } - } - - @EventListener - public void onSessionConnectEvent(SessionConnectEvent event) { - lock.lock(); - - try { - UsernamePasswordAuthenticationToken authToken = (UsernamePasswordAuthenticationToken) event.getUser(); - if (((User) authToken.getPrincipal()).getId() != null) { - long userId = ((User) authToken.getPrincipal()).getId(); - - WebSocketMessage msg; - - if (userSessionIds.get(userId) == null) { - msg = new WebSocketMessage(); - msg.setEntity(WebSocketServiceEnum.WEBSOCKET_SERVICE_INTERNAL.name()); - msg.setType(WebSocketServiceEnum.USER_CONNECT.name()); - msg.setUser((User) authToken.getPrincipal()); - msg.setSessionId(SimpAttributesContextHolder.currentAttributes().getSessionId()); - publishMessage(msg); - } - - if (userSessionIds.get(userId) == null - || !userSessionIds.get(userId).contains(SimpAttributesContextHolder.currentAttributes().getSessionId())) { - msg = new WebSocketMessage(); - msg.setEntity(WebSocketServiceEnum.WEBSOCKET_SERVICE_INTERNAL.name()); - msg.setType(WebSocketServiceEnum.SESSION_CONNECT.name()); - msg.setUser((User) authToken.getPrincipal()); - msg.setSessionId(SimpAttributesContextHolder.currentAttributes().getSessionId()); - publishMessage(msg); - } - - activeUsers.putIfAbsent(userId, authToken.getName()); - userSessionIds.putIfAbsent(userId, new HashSet<>()); - userSessionIds.get(userId).add(SimpAttributesContextHolder.currentAttributes().getSessionId()); - } - } finally { - lock.unlock(); - } - } - - @EventListener - public void onSessionDisconnectEvent(SessionDisconnectEvent event) { - lock.lock(); - - try { - User user = (User) ((UsernamePasswordAuthenticationToken) event.getUser()).getPrincipal(); - if (user.getId() != null) { - long userId = user.getId(); - - WebSocketMessage msg; - - if (userSessionIds.get(userId) != null - && userSessionIds.get(userId).contains(SimpAttributesContextHolder.currentAttributes().getSessionId())) { - msg = new WebSocketMessage(); - msg.setEntity(WebSocketServiceEnum.WEBSOCKET_SERVICE_INTERNAL.name()); - msg.setType(WebSocketServiceEnum.SESSION_DISCONNECT.name()); - msg.setUser(user); - msg.setSessionId(SimpAttributesContextHolder.currentAttributes().getSessionId()); - publishMessage(msg); - - if (userSessionIds.get(userId).size() == 1) { - msg = new WebSocketMessage(); - msg.setEntity(WebSocketServiceEnum.WEBSOCKET_SERVICE_INTERNAL.name()); - msg.setType(WebSocketServiceEnum.USER_DISCONNECT.name()); - msg.setUser(user); - msg.setSessionId(SimpAttributesContextHolder.currentAttributes().getSessionId()); - publishMessage(msg); - - activeUsers.remove(userId); - userSessionIds.remove(userId); - } - - Optional.ofNullable(userSessionIds.get(userId)) - .ifPresent(sessionSet -> { - sessionSet.remove(SimpAttributesContextHolder.currentAttributes().getSessionId()); - }); - } - } - } finally { - lock.unlock(); - } - } - - public void sendToSession(String sessionId, WebSocketMessage message) { - final SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE); - headerAccessor.setSessionId(sessionId); - headerAccessor.setLeaveMutable(true); - - simpMessagingTemplate.convertAndSendToUser(sessionId, "/queue", message, headerAccessor.getMessageHeaders()); - } - - public void addWebSocketSession(WebSocketSession session) { - lock.lock(); - - try { - webSocketSessions.put(session.getId(), session); - } finally { - lock.unlock(); - } - } - - public void removeWebSocketSession(String sessionId) { - lock.lock(); - - try { - webSocketSessions.remove(sessionId); - } finally { - lock.unlock(); - } - } - - public void sendToUser(Long userId, WebSocketMessage message) { - Optional.ofNullable(activeUsers.get(userId)) - .ifPresent(userString -> { - this.userSessionIds.get(userId).forEach(sessionId -> this.sendToSession(sessionId, message)); - }); - } - - public void sendToAll(WebSocketMessage message) { - simpMessagingTemplate.convertAndSend(message); - } - - public void sendToProjectMembers(Long projectId, WebSocketMessage message) { - final Optional optProject = projectRepository.findById(projectId); - - final Project project; - if (optProject.isPresent()) { - project = optProject.get(); - } else { - throw new RuntimeException("Cannot find Project."); - } - - project.getMembers().forEach(member -> { - this.sendToUser(member.getId(), message); - }); - } - - public void sendToProjectOwners(Long projectId, WebSocketMessage message) { - final Optional optProject = projectRepository.findById(projectId); - - final Project project; - if (optProject.isPresent()) { - project = optProject.get(); - } else { - throw new RuntimeException("Cannot find Project."); - } - - project.getOwners().forEach(owner -> { - this.sendToUser(owner.getId(), message); - }); - } - - public void sendError(String sessionId, WebSocketMessage error) { - final SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE); - headerAccessor.setSessionId(sessionId); - headerAccessor.setLeaveMutable(true); - - simpMessagingTemplate.convertAndSendToUser(sessionId, "/queue/error", error, headerAccessor.getMessageHeaders()); - - } - - public PublishSubject register(Predicate filter) { - final PublishSubject subject = PublishSubject.create(); - - serviceSubjects.put(filter, subject); - - return subject; - } - - public void closeSession(String sessionId) { - Optional.ofNullable(this.webSocketSessions.get(sessionId)) - .ifPresent(webSocketSession -> { - try { - webSocketSession.close(); - } catch (IOException ignored) { - } - }); - } - - public void closeAllUserSessions(long userId) { - Optional.ofNullable(activeUsers.get(userId)) - .ifPresent(simpUsername -> { - webSocketSessions.forEach((sessionId, session) -> { - if (session.getPrincipal().getName().equals(simpUsername)) { - try { - session.close(); - } catch (IOException ignored) { - } - } - }); - }); - } - - public long getUserIdBySessionId(String sessionId) { - final AtomicLong result = new AtomicLong(-1L); - userSessionIds.forEach((userId, sessionSet) -> { - if (sessionSet.contains(sessionId)) { - result.set(userId); - } - }); - return result.get(); - } - - private void publishMessage(WebSocketMessage msg) { - serviceSubjects.forEach((p, s) -> { - if (p.test(msg)) { - s.onNext(msg); - } - }); - } -} diff --git a/backend/src/main/java/de/learnlib/alex/websocket/services/enums/ProjectPresenceServiceEnum.java b/backend/src/main/java/de/learnlib/alex/websocket/services/enums/ProjectPresenceServiceEnum.java deleted file mode 100644 index 558925b8b..000000000 --- a/backend/src/main/java/de/learnlib/alex/websocket/services/enums/ProjectPresenceServiceEnum.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.websocket.services.enums; - -public enum ProjectPresenceServiceEnum { - PROJECT_PRESENCE_SERVICE, USER_LEFT, USER_ENTERED, STATUS_REQUEST, STATUS, ERROR -} diff --git a/backend/src/main/java/de/learnlib/alex/websocket/services/enums/SymbolPresenceServiceEnum.java b/backend/src/main/java/de/learnlib/alex/websocket/services/enums/SymbolPresenceServiceEnum.java deleted file mode 100644 index da6c929c3..000000000 --- a/backend/src/main/java/de/learnlib/alex/websocket/services/enums/SymbolPresenceServiceEnum.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.websocket.services.enums; - -public enum SymbolPresenceServiceEnum { - SYMBOL_PRESENCE_SERVICE, USER_ENTERED, USER_LEFT, STATUS, STATUS_REQUEST, ERROR -} diff --git a/backend/src/main/java/de/learnlib/alex/websocket/services/enums/TestPresenceServiceEnum.java b/backend/src/main/java/de/learnlib/alex/websocket/services/enums/TestPresenceServiceEnum.java deleted file mode 100644 index f478dac56..000000000 --- a/backend/src/main/java/de/learnlib/alex/websocket/services/enums/TestPresenceServiceEnum.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.websocket.services.enums; - -public enum TestPresenceServiceEnum { - TEST_PRESENCE_SERVICE, USER_ENTERED, USER_LEFT, STATUS, STATUS_REQUEST, ERROR -} diff --git a/backend/src/main/java/de/learnlib/alex/websocket/services/enums/WebSocketServiceEnum.java b/backend/src/main/java/de/learnlib/alex/websocket/services/enums/WebSocketServiceEnum.java deleted file mode 100644 index 55a778dea..000000000 --- a/backend/src/main/java/de/learnlib/alex/websocket/services/enums/WebSocketServiceEnum.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.websocket.services.enums; - -public enum WebSocketServiceEnum { - WEBSOCKET_SERVICE, SESSION_DISCONNECT, SESSION_CONNECT, USER_DISCONNECT, - USER_CONNECT, LOGOUT, LOGOUT_CHECK, ERROR, REQUEST_SESSION_ID, SESSION_ID, WEBSOCKET_SERVICE_INTERNAL -} diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml deleted file mode 100644 index db6844fd5..000000000 --- a/backend/src/main/resources/application.yml +++ /dev/null @@ -1,57 +0,0 @@ -spring: - jpa: - hibernate: - ddl-auto: "validate" - properties: - hibernate: - jdbc: - lob: - non_contextual_creation: true - devtools: - remote: - secret: "mysecret" - datasource: - initialization-mode: "always" - platform: "postgres" - url: "jdbc:postgresql://alex-database:5432/alex" - username: "sa" - hikari: - connection-test-query: "SELECT 1" - connection-timeout: 600000 - maximum-pool-size: 500 - max-lifetime: 1800000 - minimum-idle: 20 - validation-timeout: 3000 - idle-timeout: 60000 - servlet: - multipart: - max-file-size: "20MB" - max-request-size: "20MB" - flyway: - locations: "classpath:db/migration/postgresql" - schemas: "public" - -server: - port: 8000 - compression: - enabled: "true" - mime-types: "text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json" - min-response-size: 5120 - -alex: - filesRootDir: "/var/lib/alex/data" - version: "3.0.0" - admin: - email: "admin@alex.example" - password: "admin" - username: "admin" - -selenium: - grid: - host: "selenium-hub" - port: "4444" - -ltsmin: - path: "" - -runtime: "kubernetes" diff --git a/backend/src/main/resources/checkstyle-suppressions.xml b/backend/src/main/resources/checkstyle-suppressions.xml deleted file mode 100644 index ce8424850..000000000 --- a/backend/src/main/resources/checkstyle-suppressions.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/backend/src/main/resources/checkstyle.xml b/backend/src/main/resources/checkstyle.xml deleted file mode 100644 index f5bf6657d..000000000 --- a/backend/src/main/resources/checkstyle.xml +++ /dev/null @@ -1,355 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/backend/src/main/resources/db/migration/postgresql/V1.0__ddl.sql b/backend/src/main/resources/db/migration/postgresql/V1.0__ddl.sql deleted file mode 100644 index 8b7fa3df9..000000000 --- a/backend/src/main/resources/db/migration/postgresql/V1.0__ddl.sql +++ /dev/null @@ -1,638 +0,0 @@ -create table PROJECT -( - ID BIGINT GENERATED BY DEFAULT AS identity, - DESCRIPTION VARCHAR(250), - NAME VARCHAR(255), - primary key (ID) -); - -create table COUNTER -( - ID BIGINT GENERATED BY DEFAULT AS identity, - NAME VARCHAR(255), - VALUE INTEGER not null, - PROJECT_ID BIGINT not null, - primary key (ID), - unique (PROJECT_ID, NAME), - constraint FKAAVGL6D4NKHDCJ0V0EUSX0JJ4 - foreign key (PROJECT_ID) references PROJECT -); - -create table LTS_FORMULA_SUITE -( - ID BIGINT GENERATED BY DEFAULT AS identity, - NAME VARCHAR(255) default '', - PROJECT_ID BIGINT not null, - primary key (ID), - unique (NAME, PROJECT_ID), - constraint FKLTSFORMULASUITEPROJECT - foreign key (PROJECT_ID) references PROJECT -); - -create table LTS_FORMULA -( - ID BIGINT GENERATED BY DEFAULT AS identity, - FORMULA TEXT, - NAME TEXT, - SUITE_ID BIGINT, - primary key (ID), - constraint FKLTSFORMULALTSFORMULASUITE - foreign key (SUITE_ID) references LTS_FORMULA_SUITE -); - -create table PROJECT_ENVIRONMENT -( - ID BIGINT GENERATED BY DEFAULT AS identity, - NAME VARCHAR(255), - PROJECT_ID BIGINT not null, - IS_DEFAULT BOOLEAN default FALSE not null, - primary key (ID), - unique (PROJECT_ID, NAME), - foreign key (PROJECT_ID) references PROJECT -); - -create table PROJECT_ENVIRONMENT_VARIABLE -( - ID BIGINT GENERATED BY DEFAULT AS identity, - NAME VARCHAR(255), - VALUE VARCHAR(255), - ENVIRONMENT_ID BIGINT not null, - primary key (ID), - unique (ENVIRONMENT_ID, NAME), - foreign key (ENVIRONMENT_ID) references PROJECT_ENVIRONMENT -); - -create table PROJECT_URL -( - ID BIGINT GENERATED BY DEFAULT AS identity, - IS_DEFAULT BOOLEAN not null, - NAME VARCHAR(255), - URL VARCHAR(255), - ENVIRONMENT_ID BIGINT, - primary key (ID), - constraint FKPROJECTURLPROJECTENVIRONMENT - foreign key (ENVIRONMENT_ID) references PROJECT_ENVIRONMENT -); - -create table SETTINGS -( - ID BIGINT GENERATED BY DEFAULT AS identity, - ALLOW_USER_REGISTRATION BOOLEAN not null, - CHROME VARCHAR(255), - DEFAULT_DRIVER VARCHAR(255), - EDGE VARCHAR(255), - FIREFOX VARCHAR(255), - IE VARCHAR(255), - REMOTE VARCHAR(255), - primary key (ID) -); - -create table SYMBOL_GROUP -( - ID BIGINT GENERATED BY DEFAULT AS identity, - NAME VARCHAR(255), - PARENT_ID BIGINT, - PROJECT_ID BIGINT not null, - primary key (ID), - constraint FK3GTX3VJY2GV9APXSNQ4HWD0UL - foreign key (PARENT_ID) references SYMBOL_GROUP, - constraint FKDMVT2MUKK3DGMXJJ1GDVSW85L - foreign key (PROJECT_ID) references PROJECT -); - -create table TEST_SCREENSHOT -( - ID BIGINT GENERATED BY DEFAULT AS identity, - FILENAME VARCHAR(31) not null, - primary key (ID) -); - -create table UPLOADABLE_FILE -( - ID BIGINT GENERATED BY DEFAULT AS identity, - NAME VARCHAR(255), - PROJECT_ID BIGINT, - primary key (ID), - unique (PROJECT_ID, NAME), - constraint FKO80H1MQGB2AOG7Y6KAAUKVG4A - foreign key (PROJECT_ID) references PROJECT -); - -create table "user" -( - ID BIGINT GENERATED BY DEFAULT AS identity, - EMAIL VARCHAR(255), - PASSWORD VARCHAR(255), - ROLE INTEGER, - SALT VARCHAR(255), - USERNAME VARCHAR(32) not null, - primary key (ID), - unique (USERNAME), - unique (EMAIL) -); - -create table PROJECT_MEMBERS -( - PROJECT_ID BIGINT not null, - USER_ID BIGINT not null, - unique (USER_ID, PROJECT_ID), - constraint FK_PROJECT_MEMBERS_PROJECT_ID - foreign key (PROJECT_ID) references PROJECT, - constraint FK_PROJECT_MEMBERS_USER_ID - foreign key (USER_ID) references "user" -); - -create table PROJECT_OWNERS -( - PROJECT_ID BIGINT not null, - USER_ID BIGINT not null, - unique (USER_ID, PROJECT_ID), - constraint FK_PROJECT_OWNERS_PROJECT_ID - foreign key (PROJECT_ID) references PROJECT, - constraint FK_PROJECT_OWNERS_USER_ID - foreign key (USER_ID) references "user" -); - -create table SYMBOL -( - ID BIGINT GENERATED BY DEFAULT AS identity, - DESCRIPTION TEXT, - EXPECTED_RESULT TEXT, - HIDDEN BOOLEAN not null, - NAME VARCHAR(255), - SUCCESS_OUTPUT VARCHAR(255), - GROUP_ID BIGINT not null, - PROJECT_ID BIGINT not null, - UPDATED_ON TIMESTAMP default LOCALTIMESTAMP not null, - LAST_UPDATED_BY_ID BIGINT, - primary key (ID), - unique (PROJECT_ID, NAME), - constraint FK5S2D7OAHDDV924JQ9VSGENQQ8 - foreign key (GROUP_ID) references SYMBOL_GROUP, - constraint FKK54RHWWQEE167TAV7YB4V08BG - foreign key (PROJECT_ID) references PROJECT, - constraint FK_SYMBOL_LAST_UPDATED_BY_USER_ID - foreign key (LAST_UPDATED_BY_ID) references "user" - on delete set null -); - -create table ACTIONS -( - TYPE VARCHAR(31) not null, - ID BIGINT GENERATED BY DEFAULT AS identity, - DND_SOURCE_NODE_SELECTOR VARCHAR(255), - DND_SOURCE_NODE_TYPE INTEGER, - DND_TARGET_NODE_SELECTOR VARCHAR(255), - DND_TARGET_NODE_TYPE INTEGER, - SELECTOR TEXT, - SELECTOR_TYPE INTEGER, - ASYNC BOOLEAN, - NAME VARCHAR(255), - SCRIPT TEXT, - TIMEOUT INTEGER CHECK ( TIMEOUT >= 0 ), - INCREMENT_BY INTEGER, - "regexp" BOOLEAN, - TITLE VARCHAR(255), - DURATION BIGINT CHECK ( DURATION >= 0 ), - "value" VARCHAR(255), - COOKIE_TYPE INTEGER, - MAX_WAIT_TIME BIGINT CHECK ( MAX_WAIT_TIME >= 0 ), - OPERATOR INTEGER, - ASSERT_COUNTER_VALUE INTEGER, - VALUE_TYPE INTEGER, - STATUS INTEGER CHECK ( STATUS >= 100 ), - WAIT_CRITERION INTEGER, - OFFSETX INTEGER, - OFFSETY INTEGER, - PASSWORD VARCHAR(255), - URL VARCHAR(255), - MTH_GROUP INTEGER CHECK ( MTH_GROUP >= 0 ), - NTH_MATCH INTEGER CHECK ( NTH_MATCH >= 1 ), - REGEX VARCHAR(255), - ATTRIBUTE VARCHAR(255), - TARGET INTEGER, - JSON_TYPE INTEGER, - "key" VARCHAR(255), - FILE_NAME VARCHAR(255), - CHECK_METHOD INTEGER, - TEXT VARCHAR(255), - VARIABLE_NAME VARCHAR(255), - DOUBLE_CLICK BOOLEAN, - "schema" TEXT, - SELECT_BY INTEGER, - ACTION INTEGER, - COOKIES BYTEA, - DATA TEXT, - HEADERS BYTEA, - METHOD INTEGER, - TAG_NAME VARCHAR(255), - BROWSER_ACTION INTEGER, - SYMBOL_ID BIGINT, - BASE_URL VARCHAR(255), - LABEL VARCHAR(255), - primary key (ID), - constraint FKDYIY4JFIWRFBJ2U2RCD95Y7JC - foreign key (SYMBOL_ID) references SYMBOL -); - -create index IDXHSLP9B54F60NHNWRB5D6T0HXJ - on ACTIONS (SYMBOL_ID); - -create table PARAMETERIZED_SYMBOL -( - ID BIGINT GENERATED BY DEFAULT AS identity, - SYMBOL_ID BIGINT, - ALIAS VARCHAR(255), - primary key (ID), - constraint FKAAG4HDQOS9JACRTQNI7XA6KA1 - foreign key (SYMBOL_ID) references SYMBOL -); - -create table SYMBOL_PARAMETER -( - DTYPE VARCHAR(31) not null, - ID BIGINT GENERATED BY DEFAULT AS identity, - NAME VARCHAR(255), - PARAMETER_TYPE INTEGER, - SYMBOL_ID BIGINT, - primary key (ID), - constraint FKTPRVE66IEOEGV1KNXXWWIEU9C - foreign key (SYMBOL_ID) references SYMBOL -); - -create table SYMBOL_INPUTS -( - SYMBOL_ID BIGINT not null, - INPUTS_ID BIGINT not null, - unique (INPUTS_ID), - constraint FK4DJWA7YVHV92WN3YQNOABD422 - foreign key (INPUTS_ID) references SYMBOL_PARAMETER, - constraint FKO2EAFR9OV812YHAIO3WQXN9MC - foreign key (SYMBOL_ID) references SYMBOL -); - -create table SYMBOL_OUTPUTS -( - SYMBOL_ID BIGINT not null, - OUTPUTS_ID BIGINT not null, - unique (OUTPUTS_ID), - constraint FKEILGAEYJIQO92UWOL984DWGV2 - foreign key (OUTPUTS_ID) references SYMBOL_PARAMETER, - constraint FKSDGWTMJOK6O9H8MH01K2KEWHC - foreign key (SYMBOL_ID) references SYMBOL -); - -create table SYMBOL_OUTPUT_MAPPING -( - ID BIGINT GENERATED BY DEFAULT AS identity, - NAME VARCHAR(255) not null, - SYMBOL_PARAMETER_ID BIGINT, - primary key (ID), - constraint FKSYMBOLOUTPUTMAPPINGSYMBOLPARAMETER - foreign key (SYMBOL_PARAMETER_ID) references SYMBOL_PARAMETER -); - -create table PARAMETERIZED_SYMBOL_OUTPUT_MAPPINGS -( - PARAMETERIZED_SYMBOL_ID BIGINT not null, - OUTPUT_MAPPINGS_ID BIGINT not null, - constraint FKPARAMETERIZEDSYMBOLOUTPUTMAPPINGS_OUTPUTMAPPINGS - foreign key (PARAMETERIZED_SYMBOL_ID) references PARAMETERIZED_SYMBOL, - constraint FKPARAMETERIZEDSYMBOLOUTPUTMAPPINGS_PARAMETERIZEDSYMBOL - foreign key (OUTPUT_MAPPINGS_ID) references SYMBOL_OUTPUT_MAPPING -); - -create table SYMBOL_PARAMETER_VALUE -( - ID BIGINT GENERATED BY DEFAULT AS identity, - "value" VARCHAR(255), - SYMBOL_PARAMETER_ID BIGINT, - primary key (ID), - constraint FK9YAAYN72JOW65BO2D3DAWODBX - foreign key (SYMBOL_PARAMETER_ID) references SYMBOL_PARAMETER -); - -create table PARAMETERIZED_SYMBOL_PARAMETER_VALUES -( - PARAMETERIZED_SYMBOL_ID BIGINT not null, - PARAMETER_VALUES_ID BIGINT not null, - unique (PARAMETER_VALUES_ID), - constraint FK3BFEE54QH35FD4CJX533CGOIH - foreign key (PARAMETER_VALUES_ID) references SYMBOL_PARAMETER_VALUE, - constraint FKG25W0QJOEWFBWSUHJWFGL3UUB - foreign key (PARAMETERIZED_SYMBOL_ID) references PARAMETERIZED_SYMBOL -); - -create table SYMBOL_STEP -( - DTYPE VARCHAR(31) not null, - ID BIGINT GENERATED BY DEFAULT AS identity, - DISABLED BOOLEAN not null, - ERROR_OUTPUT VARCHAR(255), - IGNORE_FAILURE BOOLEAN not null, - NEGATED BOOLEAN not null, - POSITION INTEGER, - SYMBOL_ID BIGINT not null, - P_SYMBOL_ID BIGINT, - ACTION_ID BIGINT, - primary key (ID), - constraint FK9OULG2LGGFQIYW6YMFJMJER4F - foreign key (P_SYMBOL_ID) references PARAMETERIZED_SYMBOL, - constraint FKEB38ONQEFEDOXPU08NID8VEL4 - foreign key (SYMBOL_ID) references SYMBOL, - constraint FKQ3GBOSHKF39K83EGPYJIJ6RMO - foreign key (ACTION_ID) references ACTIONS -); - -create table TEST -( - TYPE VARCHAR(31) not null, - ID BIGINT GENERATED BY DEFAULT AS identity, - NAME VARCHAR(255), - GENERATED BOOLEAN, - PARENT_ID BIGINT, - PROJECT_ID BIGINT not null, - UPDATED_ON TIMESTAMP default LOCALTIMESTAMP not null, - LAST_UPDATED_BY_ID BIGINT, - primary key (ID), - constraint FKAEL9SAC0JYGE72OSRWUOU49I1 - foreign key (PROJECT_ID) references PROJECT, - constraint FKQ5W11J636D28D2OCHAGTXAVRQ - foreign key (PARENT_ID) references TEST, - constraint FK_TEST_CASE_LAST_UPDATED_BY_USER_ID - foreign key (LAST_UPDATED_BY_ID) references "user" - on delete set null -); - -create table TEST_CASE_STEP -( - ID BIGINT GENERATED BY DEFAULT AS identity, - EXPECTED_OUTPUT_MESSAGE VARCHAR(255) not null, - EXPECTED_OUTPUT_SUCCESS BOOLEAN not null, - EXPECTED_RESULT TEXT, - NUMBER INTEGER not null, - P_SYMBOL_ID BIGINT, - DISABLED BOOLEAN default FALSE, - primary key (ID), - constraint FKO2GS52BPSYNCKCV5BDRR1AG5H - foreign key (P_SYMBOL_ID) references PARAMETERIZED_SYMBOL -); - -create table TEST_CASE_POST_STEPS -( - TEST_CASE_ID BIGINT not null, - TEST_CASE_STEP_ID BIGINT not null, - unique (TEST_CASE_STEP_ID), - constraint FK5BRXOUI44A3UDHBO3S6M5U4X8 - foreign key (TEST_CASE_STEP_ID) references TEST_CASE_STEP, - constraint FK9RQLCYR4NJEDK3B3LOI4UCA5M - foreign key (TEST_CASE_ID) references TEST -); - -create table TEST_CASE_PRE_STEPS -( - TEST_CASE_ID BIGINT not null, - TEST_CASE_STEP_ID BIGINT not null, - unique (TEST_CASE_STEP_ID), - constraint FK4D0I1GVTBQ5I0KXSGCB5RIX9A - foreign key (TEST_CASE_STEP_ID) references TEST_CASE_STEP, - constraint FKKPON55J391L5XLEXK7I5SL3BX - foreign key (TEST_CASE_ID) references TEST -); - -create table TEST_CASE_STEPS -( - TEST_CASE_ID BIGINT not null, - TEST_CASE_STEP_ID BIGINT not null, - unique (TEST_CASE_STEP_ID), - constraint FKG3ALMGTPW7U63XJCJTUWUWH4X - foreign key (TEST_CASE_ID) references TEST, - constraint FKHU3151S7G1DHNL8E3H7IJ1UYI - foreign key (TEST_CASE_STEP_ID) references TEST_CASE_STEP -); - -create table TEST_CASE_TEST_CASE_STEP -( - TEST_CASE_ID BIGINT not null, - TEST_CASE_STEP_ID BIGINT not null, - primary key (TEST_CASE_STEP_ID), - constraint FK6N9ANES6Y6XL6HE80BQ256C2W - foreign key (TEST_CASE_ID) references TEST, - constraint FKRE6YXPW2L7C375PHX9G1OJI4Y - foreign key (TEST_CASE_STEP_ID) references TEST_CASE_STEP -); - -create table TEST_REPORT -( - ID BIGINT GENERATED BY DEFAULT AS identity, - START_DATE TIMESTAMP, - PROJECT_ID BIGINT not null, - ENVIRONMENT_ID BIGINT, - STATUS INTEGER, - DESCRIPTION TEXT, - EXECUTED_BY_ID BIGINT, - primary key (ID), - constraint FKSIR1POIGJE0JTWNN8O63F95OT - foreign key (PROJECT_ID) references PROJECT, - constraint FKTESTREPORTPROJECTENVIRONMENT - foreign key (ENVIRONMENT_ID) references PROJECT_ENVIRONMENT, - constraint FK_TEST_REPORT_EXECUTED_BY_USER_ID - foreign key (EXECUTED_BY_ID) references "user" - on delete set null -); - -create table TEST_RESULT -( - TYPE VARCHAR(31) not null, - ID BIGINT GENERATED BY DEFAULT AS identity, - TIME BIGINT not null, - FAILED_STEP BIGINT, - TEST_CASES_FAILED BIGINT, - TEST_CASES_PASSED BIGINT, - PROJECT_ID BIGINT not null, - TEST_ID BIGINT, - TEST_REPORT_ID BIGINT, - BEFORE_TEST_SCREENSHOT_ID BIGINT, - primary key (ID), - constraint FK4WGGGO81MKL0J62XUQY0MNCEQ - foreign key (TEST_REPORT_ID) references TEST_REPORT, - constraint FKEF3E8K7FGVKJ4MOX0LXRKF8HH - foreign key (TEST_ID) references TEST, - constraint FKPR4HHUECH3SA487A34VQSK46K - foreign key (PROJECT_ID) references PROJECT, - constraint FK_BEFORE_TEST_SCREENSHOT_ID - foreign key (BEFORE_TEST_SCREENSHOT_ID) references TEST_SCREENSHOT -); - -create table EXECUTE_RESULT -( - DTYPE VARCHAR(31) not null, - ID BIGINT GENERATED BY DEFAULT AS identity, - MESSAGE VARCHAR(255), - SUCCESS BOOLEAN not null, - TIME BIGINT, - TEST_RESULT_ID BIGINT not null, - SYMBOL_ID BIGINT not null, - TRACE TEXT default '', - TEST_SCREENSHOT_ID BIGINT, - primary key (ID), - constraint FKKP13F4XW3UIUWMGEJ5XSAKY68 - foreign key (SYMBOL_ID) references SYMBOL, - constraint FKNERHT22VSD7A6EO6MWFXTKO7T - foreign key (TEST_RESULT_ID) references TEST_RESULT, - constraint FK_EXECUTE_RESULT_TEST_SCREENSHOT_ID - foreign key (TEST_SCREENSHOT_ID) references TEST_SCREENSHOT - on delete set null -); - -create table WEBHOOK -( - ID BIGINT GENERATED BY DEFAULT AS identity, - NAME VARCHAR(255), - URL VARCHAR(255) not null, - USER_ID BIGINT not null, - primary key (ID), - constraint FK24YQ79VI3Y4XPNFN9FF36TYCB - foreign key (USER_ID) references "user" -); - -create table WEBHOOK_EVENTS -( - WEBHOOK_ID BIGINT not null, - EVENTS INTEGER, - constraint FKTJRLC3OHX87F7GXBR5OGCYNP0 - foreign key (WEBHOOK_ID) references WEBHOOK -); - -create table WEB_DRIVER_CONFIG -( - ID BIGINT GENERATED BY DEFAULT AS identity, - HEIGHT INTEGER not null CHECK ( HEIGHT >= 0 ), - IMPLICITLY_WAIT INTEGER not null, - PAGE_LOAD_TIMEOUT INTEGER not null, - SCRIPT_TIMEOUT INTEGER not null, - WIDTH INTEGER not null CHECK ( WIDTH >= 0 ), - HEADLESS BOOLEAN, - BROWSER VARCHAR(255), - PLATFORM INTEGER, - VERSION VARCHAR(255), - primary key (ID) -); - -create table LEARNER_SETUP -( - ID BIGINT GENERATED BY DEFAULT AS identity, - PROJECT_ID BIGINT not null, - NAME VARCHAR(255) default '', - ENABLE_CACHE BOOLEAN not null, - PRE_SYMBOL_ID BIGINT not null, - POST_SYMBOL_ID BIGINT, - ALGORITHM BYTEA not null, - EQUIVALENCE_ORACLE BYTEA not null, - WEB_DRIVER_ID BIGINT not null, - SAVED BOOLEAN default FALSE, - primary key (ID), - constraint FK_LEARNER_SETUP_POST_SYMBOL - foreign key (POST_SYMBOL_ID) references PARAMETERIZED_SYMBOL, - constraint FK_LEARNER_SETUP_PRE_SYMBOL - foreign key (PRE_SYMBOL_ID) references PARAMETERIZED_SYMBOL, - constraint FK_LEARNER_SETUP_PROJECT - foreign key (PROJECT_ID) references PROJECT, - constraint FK_LEARNER_SETUP_WEB_DRIVER - foreign key (WEB_DRIVER_ID) references WEB_DRIVER_CONFIG -); - -create table LEARNER_RESULT -( - ID BIGINT GENERATED BY DEFAULT AS identity, - COMMENT VARCHAR(255), - TEST_NO BIGINT not null, - PROJECT_ID BIGINT not null, - STATUS INTEGER, - SETUP_ID BIGINT, - EXECUTED_BY_ID BIGINT, - primary key (ID), - unique (PROJECT_ID, TEST_NO), - constraint FK7I3A026VC6CT38N8KKQKXECTP - foreign key (PROJECT_ID) references PROJECT, - constraint FK_LEARNER_RESULT_EXECUTED_BY_USER_ID - foreign key (EXECUTED_BY_ID) references "user" - on delete set null, - constraint FK_LEARNER_RESULT_LEARNER_SETUP - foreign key (SETUP_ID) references LEARNER_SETUP -); - -create table LEARNER_RESULT_STEP -( - ID BIGINT GENERATED BY DEFAULT AS identity, - ALGORITHM_INFORMATION TEXT, - COUNTER_EXAMPLE TEXT, - EQ_ORACLE BYTEA, - ERROR_TEXT VARCHAR(255), - EDGES TEXT, - INIT_NODE INTEGER, - NODES VARCHAR(255), - STATE BYTEA, - DURATION_EQ_ORACLE BIGINT, - DURATION_LEARNER BIGINT, - EQS_USED BIGINT not null, - MQS_EQ_ORACLE BIGINT, - MQS_LEARNER BIGINT, - START_DATE TIMESTAMP, - SYMBOLS_USED_EQ_ORACLE BIGINT, - SYMBOLS_USED_LEARNER BIGINT, - STEP_NO BIGINT not null, - RESULT_ID BIGINT not null, - primary key (ID), - unique (RESULT_ID, STEP_NO), - constraint FKIMQ02808EDMLKV38L6P8YG9YX - foreign key (RESULT_ID) references LEARNER_RESULT -); - -create table LEARNER_SETUP_ENVIRONMENTS -( - LEARNER_SETUP_ID BIGINT not null, - ENVIRONMENTS_ID BIGINT not null, - constraint FK_LEARNER_SETUP_ENVIRONMENTS_ENVIRONMENT - foreign key (ENVIRONMENTS_ID) references PROJECT_ENVIRONMENT, - constraint FK_LEARNER_SETUP_ENVIRONMENTS_SETUP - foreign key (LEARNER_SETUP_ID) references LEARNER_SETUP -); - -create table LEARNER_SETUP_SYMBOLS -( - LEARNER_SETUP_ID BIGINT not null, - SYMBOLS_ID BIGINT not null, - constraint FK_LEARNER_SETUP_SYMBOLS_SETUP - foreign key (LEARNER_SETUP_ID) references LEARNER_SETUP, - constraint FK_LEARNER_SETUP_SYMBOLS_SYMBOL - foreign key (SYMBOLS_ID) references PARAMETERIZED_SYMBOL -); - -create table TEST_EXECUTION_CONFIG -( - ID BIGINT GENERATED BY DEFAULT AS identity, - DRIVER_CONFIG_ID BIGINT not null, - PROJECT_ID BIGINT, - ENVIRONMENT_ID BIGINT, - IS_DEFAULT BOOLEAN, - DESCRIPTION TEXT, - primary key (ID), - constraint FKDL0WN7MAB0V5PSE0MH2MCO65F - foreign key (DRIVER_CONFIG_ID) references WEB_DRIVER_CONFIG, - constraint FKNKPXWGFT1T4B63DJ1DK9SOSIS - foreign key (PROJECT_ID) references PROJECT, - constraint FKTESTEXECUTIONCONFIGPROJECTENVIRONMENT - foreign key (ENVIRONMENT_ID) references PROJECT_ENVIRONMENT -); - -create table TEST_EXECUTION_CONFIG_TESTS -( - TEST_EXECUTION_CONFIG_ID BIGINT not null, - TESTS_ID BIGINT not null, - constraint FK5I3PCJQ5FMXKJ8XO76UULR2RE - foreign key (TESTS_ID) references TEST, - constraint FKC2LHYS0FGPGRXDY8NR8WLXDBV - foreign key (TEST_EXECUTION_CONFIG_ID) references TEST_EXECUTION_CONFIG -); - diff --git a/backend/src/main/resources/db/migration/postgresql/V1.1__model-checking-config.sql b/backend/src/main/resources/db/migration/postgresql/V1.1__model-checking-config.sql deleted file mode 100644 index 4d50c75b8..000000000 --- a/backend/src/main/resources/db/migration/postgresql/V1.1__model-checking-config.sql +++ /dev/null @@ -1,64 +0,0 @@ --- create table for model checking configs -CREATE TABLE MODEL_CHECKING_CONFIG -( - ID BIGINT GENERATED BY DEFAULT AS IDENTITY, - MIN_UNFOLDS INTEGER NOT NULL, - MULTIPLIER DOUBLE PRECISION NOT NULL, - - PRIMARY KEY (ID) -); - --- associate model checking configs with learner setups -ALTER TABLE LEARNER_SETUP - ADD COLUMN MODEL_CHECKING_CONFIG_ID BIGINT; - -ALTER TABLE LEARNER_SETUP - ADD CONSTRAINT FK_LEARNER_SETUP_MODEL_CHECKING_CONFIG - FOREIGN KEY (MODEL_CHECKING_CONFIG_ID) REFERENCES MODEL_CHECKING_CONFIG; - --- create a model checking config for each learner setup -DO -$$ - DECLARE - learnerSetupRecord RECORD; - configId BIGINT; - BEGIN - FOR learnerSetupRecord IN SELECT * FROM LEARNER_SETUP - LOOP - INSERT INTO MODEL_CHECKING_CONFIG (MIN_UNFOLDS, MULTIPLIER) VALUES (1, 0.1) RETURNING ID INTO configId; - UPDATE LEARNER_SETUP SET MODEL_CHECKING_CONFIG_ID = configId WHERE ID = learnerSetupRecord.ID; - END LOOP; - END; -$$; - --- create association table for model checking config -> ltl formula suites -CREATE TABLE MODEL_CHECKING_CONFIG_FORMULA_SUITES -( - MODEL_CHECKING_CONFIG_ID BIGINT NOT NULL, - FORMULA_SUITES_ID BIGINT NOT NULL, - - FOREIGN KEY (MODEL_CHECKING_CONFIG_ID) REFERENCES MODEL_CHECKING_CONFIG, - FOREIGN KEY (FORMULA_SUITES_ID) REFERENCES LTS_FORMULA_SUITE -); - --- create table for model checking result -CREATE TABLE MODEL_CHECKING_RESULT -( - ID BIGINT GENERATED BY DEFAULT AS IDENTITY, - FORMULA_ID BIGINT NOT NULL, - PREFIX TEXT[], - LOOP TEXT[], - - PRIMARY KEY (ID), - FOREIGN KEY (FORMULA_ID) REFERENCES LTS_FORMULA -); - --- create association table for learner result step -> model checking results -CREATE TABLE LEARNER_RESULT_STEP_MODEL_CHECKING_RESULTS -( - LEARNER_RESULT_STEP_ID BIGINT NOT NULL, - MODEL_CHECKING_RESULTS_ID BIGINT NOT NULL, - - FOREIGN KEY (LEARNER_RESULT_STEP_ID) REFERENCES LEARNER_RESULT_STEP, - FOREIGN KEY (MODEL_CHECKING_RESULTS_ID) REFERENCES MODEL_CHECKING_RESULT -) \ No newline at end of file diff --git a/backend/src/main/resources/db/migration/postgresql/V1.2__processes-per-user.sql b/backend/src/main/resources/db/migration/postgresql/V1.2__processes-per-user.sql deleted file mode 100644 index 036c5ec1f..000000000 --- a/backend/src/main/resources/db/migration/postgresql/V1.2__processes-per-user.sql +++ /dev/null @@ -1,12 +0,0 @@ --- Add max allowed processes to user -ALTER TABLE "user" - ADD COLUMN max_allowed_processes INTEGER DEFAULT 1; - --- Populate new column with default values on exiting rows --- noinspection SqlWithoutWhere -UPDATE "user" -SET max_allowed_processes = 1; - --- Add not null constraint -ALTER TABLE "user" - ALTER COLUMN max_allowed_processes SET NOT NULL; \ No newline at end of file diff --git a/backend/src/main/resources/db/migration/postgresql/V1.3__export-test-configs.sql b/backend/src/main/resources/db/migration/postgresql/V1.3__export-test-configs.sql deleted file mode 100644 index 2af09458e..000000000 --- a/backend/src/main/resources/db/migration/postgresql/V1.3__export-test-configs.sql +++ /dev/null @@ -1,3 +0,0 @@ --- Add name to testExecutionConfigs -ALTER TABLE test_execution_config - ADD COLUMN name VARCHAR(255) default ''; \ No newline at end of file diff --git a/backend/src/main/resources/db/migration/postgresql/V1.4__symbol-name-constraint.sql b/backend/src/main/resources/db/migration/postgresql/V1.4__symbol-name-constraint.sql deleted file mode 100644 index 66929b565..000000000 --- a/backend/src/main/resources/db/migration/postgresql/V1.4__symbol-name-constraint.sql +++ /dev/null @@ -1,8 +0,0 @@ --- Drop unique name in project constraint -ALTER TABLE symbol - DROP CONSTRAINT symbol_project_id_name_key; - --- Add new name in group unique constraint -ALTER TABLE symbol - ADD CONSTRAINT symbol_group_id_name_key - UNIQUE (group_id, name) \ No newline at end of file diff --git a/backend/src/main/resources/db/migration/postgresql/V1.5__test-name-constraint.sql b/backend/src/main/resources/db/migration/postgresql/V1.5__test-name-constraint.sql deleted file mode 100644 index 70f6a909a..000000000 --- a/backend/src/main/resources/db/migration/postgresql/V1.5__test-name-constraint.sql +++ /dev/null @@ -1,4 +0,0 @@ --- Add unique constraint (name, parent_id) -ALTER TABLE test - ADD CONSTRAINT test_name_parent_id_key - UNIQUE (name, parent_id); \ No newline at end of file diff --git a/backend/src/main/resources/db/migration/postgresql/V1.6__webhook-header.sql b/backend/src/main/resources/db/migration/postgresql/V1.6__webhook-header.sql deleted file mode 100644 index 97ef7fed7..000000000 --- a/backend/src/main/resources/db/migration/postgresql/V1.6__webhook-header.sql +++ /dev/null @@ -1,25 +0,0 @@ --- Add header field to webhooks -ALTER TABLE webhook - ADD COLUMN headers bytea; - --- Add request method to webhooks -ALTER TABLE webhook - ADD COLUMN method integer; - --- Add onetime indicator to webhooks -ALTER TABLE webhook - ADD COLUMN once boolean; - --- Update webhooks -UPDATE webhook - SET method = 1; - -UPDATE webhook - SET once = false; - --- Set constraints -ALTER TABLE webhook - ALTER COLUMN method SET NOT NULL; - -ALTER TABLE webhook - ALTER COLUMN once SET NOT NULL; \ No newline at end of file diff --git a/backend/src/main/resources/db/migration/postgresql/V1.7__learner-result-error-message.sql b/backend/src/main/resources/db/migration/postgresql/V1.7__learner-result-error-message.sql deleted file mode 100644 index 615989b21..000000000 --- a/backend/src/main/resources/db/migration/postgresql/V1.7__learner-result-error-message.sql +++ /dev/null @@ -1 +0,0 @@ -alter table LEARNER_RESULT add column ERROR_MESSAGE text default ''; diff --git a/backend/src/main/resources/db/migration/postgresql/V1.8__kubernetes-autoscaling.sql b/backend/src/main/resources/db/migration/postgresql/V1.8__kubernetes-autoscaling.sql deleted file mode 100644 index a840cf7a9..000000000 --- a/backend/src/main/resources/db/migration/postgresql/V1.8__kubernetes-autoscaling.sql +++ /dev/null @@ -1,3 +0,0 @@ -alter table "user" drop column SALT; -alter table WEB_DRIVER_CONFIG drop column HEADLESS; -alter table SETTINGS add column RUNTIME varchar(255); diff --git a/backend/src/main/resources/images/logo.png b/backend/src/main/resources/images/logo.png deleted file mode 100644 index 6612eeac1..000000000 Binary files a/backend/src/main/resources/images/logo.png and /dev/null differ diff --git a/backend/src/test/java/de/learnlib/alex/auth/dao/UserDAOTest.java b/backend/src/test/java/de/learnlib/alex/auth/dao/UserDAOTest.java deleted file mode 100644 index b0646ee70..000000000 --- a/backend/src/test/java/de/learnlib/alex/auth/dao/UserDAOTest.java +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.auth.dao; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.auth.entities.UserRole; -import de.learnlib.alex.auth.repositories.UserRepository; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.dao.FileDAO; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.websocket.services.WebSocketService; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import javax.persistence.EntityManager; -import javax.validation.ConstraintViolationException; -import javax.validation.ValidationException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.BDDMockito; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class UserDAOTest { - - private static final int TEST_USER_COUNT = 3; - - @Mock - private UserRepository userRepository; - - @Mock - private FileDAO fileDAO; - - @Mock - private ProjectDAO projectDAO; - - @Mock - private ProjectRepository projectRepository; - - @Mock - private WebSocketService webSocketService; - - @Mock - private EntityManager entityManager; - - private UserDAO userDAO; - - private User dummyAdmin; - - @BeforeEach - public void setUp() throws NotFoundException { - userDAO = new UserDAO(userRepository, fileDAO, projectDAO, projectRepository, - webSocketService, entityManager); - dummyAdmin = new User(); - dummyAdmin.setRole(UserRole.ADMIN); - dummyAdmin.setId(-1L); - } - - @Test - public void shouldCreateAValidUser() throws NotFoundException { - User user = createUser(); - - userDAO.create(user); - - Mockito.verify(userRepository).save(user); - } - - @Test - public void shouldHandleConstraintViolationExceptionOnUserCreationGracefully() { - User user = createUser(); - BDDMockito.given(userRepository.save(user)).willThrow(ConstraintViolationException.class); - assertThrows(ValidationException.class, () -> userDAO.create(user)); - } - - @Test - public void shouldGetAllUsers() { - List users = createUsersList(); - BDDMockito.given(userRepository.findAll()).willReturn(users); - - List allUsers = userDAO.getAll(); - - assertEquals(users.size(), allUsers.size()); - for (User u : allUsers) { - assertTrue(users.contains(u)); - } - } - - @Test - public void shouldOnlyGetAllAdmins() { - List users = createUsersList(); - BDDMockito.given(userRepository.findByRole(UserRole.ADMIN)).willReturn(users); - - List allAdmins = userDAO.getAllByRole(UserRole.ADMIN); - - assertEquals(users.size(), allAdmins.size()); - for (User u : allAdmins) { - assertTrue(users.contains(u)); - } - } - - @Test - public void shouldGetAllRegisteredUsers() { - List users = createUsersList(); - BDDMockito.given(userRepository.findByRole(UserRole.REGISTERED)).willReturn(users); - - List allRegistered = userDAO.getAllByRole(UserRole.REGISTERED); - - assertEquals(users.size(), allRegistered.size()); - for (User u : allRegistered) { - assertTrue(users.contains(u)); - } - } - - @Test - public void shouldGetByID() throws NotFoundException { - User user = createUser(); - BDDMockito.given(userRepository.findById(user.getId())).willReturn(Optional.of(user)); - - User userFromDB = userDAO.getByID(user.getId()); - - assertEquals(user, userFromDB); - } - - @Test - public void shouldThrowAnExceptionIfTheUserCanNotBeFoundByID() { - assertThrows(NotFoundException.class, () -> userDAO.getByID((long) -1)); - } - - @Test - public void shouldGetByEmail() { - User user = createUser(); - BDDMockito.given(userRepository.findOneByEmail(user.getEmail())).willReturn(Optional.of(user)); - - User userFromDB = userDAO.getByEmail(user.getEmail()); - - assertEquals(user, userFromDB); - } - - @Test - public void shouldThrowAnExceptionIfTheUserCanNotBeFoundByEmail() throws NotFoundException { - User user = createUser(); - - BDDMockito.given(userRepository.findOneByEmail(user.getEmail())) - .willReturn(Optional.empty()); - - assertThrows(NotFoundException.class, () -> userDAO.getByEmail(user.getEmail())); - } - - @Test - public void shouldGetByUsername() throws NotFoundException { - User user = createUser(); - - BDDMockito.given(userRepository.findOneByUsername(user.getUsername())) - .willReturn(Optional.of(user)); - - User userFromDB = userDAO.getByUsername(user.getUsername()); - - assertEquals(user, userFromDB); - } - - @Test - public void shouldThrowAnExceptionIfTheUserCanNotBeFoundByUsername() throws NotFoundException { - User user = createUser(); - - BDDMockito.given(userRepository.findOneByUsername(user.getUsername())) - .willReturn(Optional.empty()); - - assertThrows(NotFoundException.class, () -> userDAO.getByUsername(user.getUsername())); - } - - @Test - public void shouldUpdateAUser() throws NotFoundException { - User user = createUser(); - - userDAO.update(user); - - Mockito.verify(userRepository).save(user); - } - - @Test - public void shouldHandleConstraintViolationExceptionOnUserUpdateGracefully() { - User user = createUser(); - BDDMockito.given(userRepository.save(user)).willThrow(ConstraintViolationException.class); - assertThrows(ValidationException.class, () -> userDAO.update(user)); - } - - @Test - public void shouldDeleteARegisteredUser() throws NotFoundException { - User user = createUser(); - user.setId(42L); - BDDMockito.given(userRepository.findById(user.getId())).willReturn(Optional.of(user)); - - userDAO.delete(dummyAdmin, user.getId()); - - Mockito.verify(userRepository).delete(user); - } - - @Test - public void shouldDeleteAnAdminIfThereAreMoreThanOne() { - List admins = createUsersList(); - admins.forEach(u -> u.setRole(UserRole.ADMIN)); - User adminToDelete = admins.get(0); - adminToDelete.setId(42L); - BDDMockito.given(userRepository.findById(adminToDelete.getId())).willReturn(Optional.of(adminToDelete)); - BDDMockito.given(userRepository.findByRole(UserRole.ADMIN)).willReturn(admins); - userDAO.delete(dummyAdmin, adminToDelete.getId()); - Mockito.verify(userRepository).delete(adminToDelete); - } - - @Test - public void shouldNotDeleteTheLastAdmin() { - User admin = createAdmin(); - BDDMockito.given(userRepository.findById(admin.getId())).willReturn(Optional.of(admin)); - BDDMockito.given(userRepository.findByRole(UserRole.ADMIN)).willReturn(Collections.singletonList(admin)); - assertThrows(NotFoundException.class, () -> userDAO.delete(dummyAdmin, admin.getId())); - } - - @Test - public void shouldDeleteMultipleUsers() { - User user1 = new User(); - user1.setId(42L); - user1.setEmail("user1@mail.de"); - user1.setPassword("test"); - - User user2 = new User(); - user2.setId(21L); - user2.setEmail("user2@mail.de"); - user2.setPassword("test"); - - BDDMockito.given(userRepository.findAllByIdIn(Arrays.asList(user1.getId(), user2.getId()))) - .willReturn(Arrays.asList(user1, user2)); - - userDAO.delete(dummyAdmin, Arrays.asList(user1.getId(), user2.getId())); - - assertEquals(userDAO.getAllByRole(UserRole.REGISTERED).size(), 0); - } - - @Test - public void shouldNotDeleteMultipleUsersOnNotFound() { - User user1 = new User(); - user1.setId(42L); - user1.setEmail("user1@mail.de"); - user1.setUsername("user1"); - user1.setPassword("test"); - - userDAO.create(user1); - assertThrows(NotFoundException.class, () -> userDAO.delete(dummyAdmin, Collections.singletonList(user1.getId()))); - } - - @Test - public void shouldFailToDeleteAUserOnInvalidId() { - assertThrows(NotFoundException.class, () -> userDAO.delete(dummyAdmin, -1L)); - } - - @Test - public void shouldNotDeleteOnlyExistingAdmin() { - User admin = createAdmin(); - assertThrows(NotFoundException.class, () -> userDAO.delete(dummyAdmin, admin.getId())); - } - - private User createUser() { - User user = new User(); - user.setUsername("user"); - user.setEmail("user@text.example"); - user.setPassword("alex"); - return user; - } - - private User createAdmin() { - User admin = createUser(); - admin.setRole(UserRole.ADMIN); - return admin; - } - - private List createUsersList() { - List users = new ArrayList<>(); - for (int i = 0; i < TEST_USER_COUNT; i++) { - User u = new User(); - u.setEmail("user-" + i + "@mail.de"); - u.setPassword("test"); - users.add(u); - } - return users; - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/auth/entities/UserTest.java b/backend/src/test/java/de/learnlib/alex/auth/entities/UserTest.java deleted file mode 100644 index 03407e037..000000000 --- a/backend/src/test/java/de/learnlib/alex/auth/entities/UserTest.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.auth.entities; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.jayway.jsonpath.JsonPath; -import com.jayway.jsonpath.PathNotFoundException; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.webhooks.entities.Webhook; -import java.util.Collections; -import org.json.JSONException; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; -import org.junit.jupiter.params.provider.ValueSource; -import org.skyscreamer.jsonassert.JSONAssert; - -public class UserTest { - - private static ObjectMapper om; - - @BeforeAll - public static void setUp() { - om = new ObjectMapper(); - } - - @Test - public void shouldInitializeUserWithDefaultRole() { - final User user = new User(); - assertEquals(user.getRole(), UserRole.REGISTERED); - } - - @ParameterizedTest(name = "Use the value {0} for the test") - @ValueSource(strings = { "password", "salt" }) - public void shouldNotLeakSensibleDataWhenSerialized(String property) throws JsonProcessingException { - final User user = new User(); - user.setPassword("password"); - - final String userString = om.writeValueAsString(user); - assertThrows(PathNotFoundException.class, () -> JsonPath.read(userString, "$." + property)); - } - - @Test - public void shouldSerializeCorrectly() throws JsonProcessingException, JSONException { - final User user = new User(); - user.setId(1L); - user.setUsername("user1"); - user.setPassword("password123"); - user.setRole(UserRole.ADMIN); - user.setEmail("admin@alex.com"); - - final String userString = om.writeValueAsString(user); - final String expectedUserString = "{\"id\":1, \"username\": \"user1\", \"email\": \"admin@alex.com\", \"role\": \"ADMIN\", \"maxAllowedProcesses\":1}"; - JSONAssert.assertEquals(expectedUserString, userString, true); - } - - @Test - public void shouldNotSerializeProjects() { - final Project p1 = new Project(); - p1.setId(2L); - final Project p2 = new Project(); - p2.setId(3L); - - final User user = new User(); - user.setId(1L); - user.setUsername("user"); - user.setEmail("user@alex.com"); - user.setProjectsOwner(Collections.singleton(p1)); - user.setProjectsMember(Collections.singleton(p2)); - - assertThrows(PathNotFoundException.class, () -> { - final String userString = om.writeValueAsString(user); - JsonPath.read(userString, "projectsMember"); - JsonPath.read(userString, "projectsOwner"); - }); - } - - @Test - public void shouldNotSerializeWebhooks() { - final Webhook w = new Webhook(); - w.setId(2L); - - final User user = new User(); - user.setId(1L); - user.setUsername("user"); - user.setEmail("user@alex.com"); - user.setWebhooks(Collections.singletonList(w)); - - assertThrows(PathNotFoundException.class, () -> { - final String userString = om.writeValueAsString(user); - JsonPath.read(userString, "webhooks"); - }); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/common/utils/CSSUtilsTest.java b/backend/src/test/java/de/learnlib/alex/common/utils/CSSUtilsTest.java deleted file mode 100644 index f15f85dca..000000000 --- a/backend/src/test/java/de/learnlib/alex/common/utils/CSSUtilsTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.common.utils; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.Test; - -public class CSSUtilsTest { - - @Test - public void shouldLeaveUncriticalSelectorsUntouched() { - final String s1 = ".some-class"; - assertEquals(".some-class", CSSUtils.escapeSelector(s1)); - - final String s2 = "body"; - assertEquals("body", CSSUtils.escapeSelector(s2)); - - final String s3 = "body > div > ul:nth-child(3)"; - assertEquals("body > div > ul:nth-child(3)", CSSUtils.escapeSelector(s3)); - - final String s4 = "#some-element"; - assertEquals("#some-element", CSSUtils.escapeSelector(s4)); - } - - @Test - public void shouldEscapeIdsWithSpecialCharacters() { - final String[] specialChars = {"!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", ".", "/", ":", ";", - "<", "=", ">", "?", "@", "[", "\\", "]", "^", "`", "{", "|", "}", "~"}; - - for (String specialChar : specialChars) { - final String s1 = "#some" + specialChar + "el"; - assertEquals("#some\\" + specialChar + "el", CSSUtils.escapeSelector(s1)); - - final String s2 = "body > #some" + specialChar + "el"; - assertEquals("body > #some\\" + specialChar + "el", CSSUtils.escapeSelector(s2)); - } - } -} diff --git a/backend/src/test/java/de/learnlib/alex/common/utils/JSONHelpersTest.java b/backend/src/test/java/de/learnlib/alex/common/utils/JSONHelpersTest.java deleted file mode 100644 index b2bbb2dcb..000000000 --- a/backend/src/test/java/de/learnlib/alex/common/utils/JSONHelpersTest.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.common.utils; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; - -import de.learnlib.alex.data.entities.actions.rest.CheckAttributeTypeAction.JsonType; -import org.junit.jupiter.api.Test; - -public class JSONHelpersTest { - - private static final String JSON = "{\"field\": 2}"; - - @Test - public void shouldAlwaysGetTheCorrectAttributeValue() { - String json2 = "[{\"field\": 1}]"; - String json3 = "{\"field\": [{\"sub\": 0}]}"; - String json4 = "{\"field\": {\"sub\": 0}}"; - String json5 = "{\"field\":true}"; - - assertEquals("2", JSONHelpers.getAttributeValue(JSON, "$.field")); - assertEquals("1", JSONHelpers.getAttributeValue(json2, "$[0].field")); - assertEquals("0", JSONHelpers.getAttributeValue(json3, "$.field[0].sub")); - assertEquals("0", JSONHelpers.getAttributeValue(json4, "$.field.sub")); - assertEquals("true", JSONHelpers.getAttributeValue(json5, "$.field")); - } - - @Test - public void shouldReturnSerializedJSONString() { - final var json = "{\"field\":{\"sub\":0}}"; - final var result = JSONHelpers.getAttributeValue(json, "field"); - assertEquals("{\"sub\":0}", result); - } - - @Test - public void shouldReturnNullIfJSONIsEmptyOnGetValue() { - assertNull(JSONHelpers.getAttributeValue("", "field")); - } - - @Test - public void shouldReturnNullIfJSONIsInvalidOnGetValue() { - assertNull(JSONHelpers.getAttributeValue("{\"foo\": \"bar\" \"field\": \"Test\"}", "field")); - } - - @Test - public void shouldReturnNullIfJSONIsNotEvenCloseToProperJSONOnGetValue() { - assertNull(JSONHelpers.getAttributeValue("this is not real json", "field")); - } - - @Test - public void shouldReturnNullIfJSONPathIsInvalidOnGetValue() { - assertNull(JSONHelpers.getAttributeValue(JSON, "(field")); - } - - @Test - public void shouldGetTheTypeStringCorrectly() { - String json = "{\"field\": \"stringggg\"}"; - - assertEquals(JSONHelpers.getAttributeType(json, "field"), JsonType.STRING); - } - - @Test - public void shouldGetTheTypeNumberCorrectly1() { - String json = "{\"field\": 1}"; - - assertEquals(JSONHelpers.getAttributeType(json, "field"), JsonType.INTEGER); - } - - @Test - public void shouldGetTheTypeNumberCorrectly2() { - String json = "{\"field\": 1.2}"; - - assertEquals(JSONHelpers.getAttributeType(json, "field"), JsonType.INTEGER); - } - - @Test - public void shouldGetTheTypeTrueCorrectly() { - String json = "{\"field\": true}"; - - assertEquals(JSONHelpers.getAttributeType(json, "field"), JsonType.BOOLEAN); - } - - @Test - public void shouldGetTheTypeFalseCorrectly() { - String json = "{\"field\": false}"; - - assertEquals(JSONHelpers.getAttributeType(json, "field"), JsonType.BOOLEAN); - } - - @Test - public void shouldGetTheTypeObjectCorrectly1() { - String json = "{\"field\": {}}"; - - assertEquals(JSONHelpers.getAttributeType(json, "field"), JsonType.OBJECT); - } - - @Test - public void shouldGetTheTypeArrayCorrectly1() { - String json = "{\"field\": []}"; - - assertEquals(JSONHelpers.getAttributeType(json, "field"), JsonType.ARRAY); - } - - @Test - public void shouldGetTheTypeNullCorrectly1() { - String json = "{\"field\": null}"; - - assertEquals(JSONHelpers.getAttributeType(json, "field"), JsonType.NULL); - } - - @Test - public void shouldReturnCorrectTypeIfJSONIsNotStrictJSONOnGetType() { - assertEquals(JsonType.STRING, JSONHelpers.getAttributeType("{field: Test}", "field")); - } - - @Test - public void shouldReturnNullIfJSONIsEmptyOnGetType() { - assertNull(JSONHelpers.getAttributeType("", "$.field")); - } - - @Test - public void shouldReturnNullIfJSONIsNotEvenCloseToProperJSONOnGetType() { - assertNull(JSONHelpers.getAttributeType("this is not real json", "field")); - } - - @Test - public void shouldReturnNullIfJSONIsInvalidOnGetType() { - assertNull(JSONHelpers.getAttributeType("{\"foo\": \"bar\" \"field\": \"Test\"}", "$.field")); - } - - @Test - public void shouldReturnNullIfJSONPathIsInvalidOnGetType() { - assertNull(JSONHelpers.getAttributeType(JSON, "!=field")); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/common/utils/SearchHelperTest.java b/backend/src/test/java/de/learnlib/alex/common/utils/SearchHelperTest.java deleted file mode 100644 index 76279f39c..000000000 --- a/backend/src/test/java/de/learnlib/alex/common/utils/SearchHelperTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.common.utils; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.data.entities.ProjectEnvironmentVariable; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.CounterStoreConnector; -import de.learnlib.alex.learning.services.connectors.FileStoreConnector; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import org.junit.jupiter.api.Test; - -public class SearchHelperTest { - - private static final Long PROJECT_ID = 10L; - private static final int COUNTER_VALUE = 42; - - @Test - public void shouldReplaceVariablesCorrectly() { - VariableStoreConnector variables = mock(VariableStoreConnector.class); - given(variables.get("name")).willReturn("Jon Doe"); - CounterStoreConnector counter = mock(CounterStoreConnector.class); - given(counter.get("counter")).willReturn(COUNTER_VALUE); - ConnectorManager connector = mock(ConnectorManager.class); - WebSiteConnector webSiteConnector = mock(WebSiteConnector.class); - FileStoreConnector fileStoreConnector = mock(FileStoreConnector.class); - given(fileStoreConnector.getAbsoluteFileLocation(PROJECT_ID, "file.txt")).willReturn("/dir/file.text"); - given(connector.getConnector(VariableStoreConnector.class)).willReturn(variables); - given(connector.getConnector(CounterStoreConnector.class)).willReturn(counter); - given(connector.getConnector(WebSiteConnector.class)).willReturn(webSiteConnector); - given(connector.getConnector(FileStoreConnector.class)).willReturn(fileStoreConnector); - - String result = - SearchHelper.insertVariableValues(connector, PROJECT_ID, "Hello {{$name}}, you are {{user}} no. {{#counter}} and want to upload file {{\\file.txt}} that belongs to {{$name}}!"); - - assertEquals("Hello Jon Doe, you are {{user}} no. " + COUNTER_VALUE + " and want to upload file /dir/file.text that belongs to Jon Doe!", result); - } - - @Test - public void shouldNotReplaceAnythingIfTextContainsNoVariables() { - ConnectorManager connector = mock(ConnectorManager.class); - - String result = SearchHelper.insertVariableValues(connector, PROJECT_ID, "Hello Jon Doe, you are user no. 42!"); - - assertEquals("Hello Jon Doe, you are user no. " + COUNTER_VALUE + "!", result); - } - - @Test - public void shouldReplaceEnvironmentVariables() { - final ProjectEnvironmentVariable variable = new ProjectEnvironmentVariable(); - variable.setName("TEST"); - variable.setValue("muffin"); - - final ProjectEnvironment environment = new ProjectEnvironment(); - environment.getVariables().add(variable); - - final ConnectorManager connectors = new ConnectorManager(environment); - - final String result = SearchHelper.insertVariableValues(connectors, PROJECT_ID, "env: {{:TEST}}"); - assertEquals("env: muffin", result); - } - - @Test - public void shouldEscapeDollarSignAndBackSlashInVariableValues() { - final ConnectorManager connector = mock(ConnectorManager.class); - final VariableStoreConnector variables = mock(VariableStoreConnector.class); - - given(variables.get("text")).willReturn("text with $ and \\ sign"); - given(connector.getConnector(VariableStoreConnector.class)).willReturn(variables); - - final String result = SearchHelper.insertVariableValues(connector, PROJECT_ID, "this is a {{$text}}"); - - assertEquals("this is a text with $ and \\ sign", result); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/dao/CounterDAOTest.java b/backend/src/test/java/de/learnlib/alex/data/dao/CounterDAOTest.java deleted file mode 100644 index ba2e87a3a..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/dao/CounterDAOTest.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.dao; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.verify; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.entities.Counter; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.repositories.CounterRepository; -import de.learnlib.alex.data.repositories.ProjectRepository; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class CounterDAOTest { - - private static final long USER_ID = 21L; - private static final long PROJECT_ID = 42L; - private static final String COUNTER_NAME = "CounterNo1"; - private static final Integer COUNTER_VALUE = 123; - private static final int AMOUNT_OF_COUNTERS = 3; - - @Mock - private ProjectDAO projectDAO; - - @Mock - private CounterRepository counterRepository; - - @Mock - private ProjectRepository projectRepository; - - private CounterDAO counterDAO; - - @BeforeEach - public void setUp() { - counterDAO = new CounterDAO(projectDAO, counterRepository, projectRepository); - } - - @Test - public void shouldCreateACounter() { - User user = new User(); - - Project project = new Project(); - project.setId(PROJECT_ID); - - given(projectRepository.getOne(PROJECT_ID)).willReturn(project); - - Counter counter = new Counter(); - counter.setName(COUNTER_NAME); - counter.setValue(COUNTER_VALUE); - - counterDAO.create(user, PROJECT_ID, counter); - - verify(counterRepository).save(any(Counter.class)); - } - - @Test - public void shouldGetAllCounterOfAProject() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - - List counters = createCounterList(); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(counterRepository.findAllByProject(project)).willReturn(counters); - - List allCounters = counterDAO.getAll(user, PROJECT_ID); - - assertEquals(counters.size(), allCounters.size()); - for (Counter c : allCounters) { - assertTrue(counters.contains(c)); - } - } - - @Test - public void shouldUpdateACounter() { - final Long counterId = 1L; - - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.setId(PROJECT_ID); - - Counter counter = new Counter(); - counter.setProject(project); - counter.setName(COUNTER_NAME); - counter.setId(counterId); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(counterRepository.findById(counterId)).willReturn(Optional.of(counter)); - - counterDAO.update(user, counter); - - verify(counterRepository).save(counter); - } - - @Test - public void shouldDeleteACounter() { - final Long counterId = 1L; - - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.setId(PROJECT_ID); - - Counter counter = new Counter(); - counter.setId(counterId); - counter.setProject(project); - List counterAsList = Collections.singletonList(counter); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(counterRepository.findAllByIdIn(Collections.singletonList(counterId))).willReturn(counterAsList); - - counterDAO.delete(user, PROJECT_ID, Collections.singletonList(counterId)); - - verify(counterRepository).deleteAll(counterAsList); - } - - @Test - public void shouldFailToDeleteACounterThatDoesNotExist() { - User user = new User(); - assertThrows(NotFoundException.class, () -> counterDAO.delete(user, PROJECT_ID, Collections.singletonList(-1L))); - } - - private List createCounterList() { - List counters = new ArrayList<>(); - for (int i = 0; i < AMOUNT_OF_COUNTERS; i++) { - Counter c = new Counter(); - counters.add(c); - } - return counters; - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/dao/ProjectDAOTest.java b/backend/src/test/java/de/learnlib/alex/data/dao/ProjectDAOTest.java deleted file mode 100644 index 68afb3e2e..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/dao/ProjectDAOTest.java +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.dao; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.verify; - -import de.learnlib.alex.auth.dao.UserDAO; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.repositories.ParameterizedSymbolRepository; -import de.learnlib.alex.data.repositories.ProjectEnvironmentRepository; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.data.repositories.ProjectUrlRepository; -import de.learnlib.alex.data.repositories.SymbolActionRepository; -import de.learnlib.alex.data.repositories.SymbolParameterRepository; -import de.learnlib.alex.data.repositories.SymbolStepRepository; -import de.learnlib.alex.data.repositories.UploadableFileRepository; -import de.learnlib.alex.learning.dao.LearnerSetupDAO; -import de.learnlib.alex.learning.repositories.LearnerResultRepository; -import de.learnlib.alex.learning.repositories.LearnerResultStepRepository; -import de.learnlib.alex.learning.repositories.LearnerSetupRepository; -import de.learnlib.alex.modelchecking.dao.LtsFormulaDAO; -import de.learnlib.alex.modelchecking.dao.LtsFormulaSuiteDAO; -import de.learnlib.alex.testing.dao.TestDAO; -import de.learnlib.alex.testing.dao.TestExecutionConfigDAO; -import de.learnlib.alex.testing.dao.TestReportDAO; -import de.learnlib.alex.testing.repositories.TestExecutionConfigRepository; -import de.learnlib.alex.testing.repositories.TestReportRepository; -import de.learnlib.alex.testing.repositories.TestRepository; -import de.learnlib.alex.websocket.services.ProjectPresenceService; -import de.learnlib.alex.websocket.services.SymbolPresenceService; -import de.learnlib.alex.websocket.services.TestPresenceService; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import javax.validation.ConstraintViolationException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class ProjectDAOTest { - - private static final long USER_ID = 21L; - private static final long PROJECT_ID = 42L; - private static final int TEST_PROJECT_COUNT = 3; - - @Mock - private ProjectRepository projectRepository; - - @Mock - private FileDAO fileDAO; - - @Mock - private LearnerResultRepository learnerResultRepository; - - @Mock - private TestReportRepository testReportRepository; - - @Mock - private SymbolStepRepository symbolStepRepository; - - @Mock - private ParameterizedSymbolRepository parameterizedSymbolRepository; - - @Mock - private SymbolActionRepository symbolActionRepository; - - @Mock - private ProjectEnvironmentDAO environmentDAO; - - @Mock - private ProjectUrlRepository projectUrlRepository; - - @Mock - private TestExecutionConfigRepository testExecutionConfigRepository; - - @Mock - private ProjectEnvironmentRepository environmentRepository; - - @Mock - private TestDAO testDAO; - - @Mock - private SymbolGroupDAO symbolGroupDAO; - - @Mock - private UserDAO userDAO; - - @Mock - private TestRepository testRepository; - - @Mock - private SymbolParameterRepository symbolParameterRepository; - - @Mock - private UploadableFileRepository uploadableFileRepository; - - @Mock - private LearnerSetupRepository learnerSetupRepository; - - @Mock - private SymbolPresenceService symbolPresenceService; - - @Mock - private TestPresenceService testPresenceService; - - @Mock - private ProjectPresenceService projectPresenceService; - - @Mock - private TestReportDAO testReportDAO; - - @Mock - private LtsFormulaSuiteDAO ltsFormulaSuiteDAO; - - @Mock - private LtsFormulaDAO ltsFormulaDAO; - - @Mock - private LearnerResultStepRepository learnerResultStepRepository; - - @Mock - private LearnerSetupDAO learnerSetupDAO; - - @Mock - private TestExecutionConfigDAO testExecutionConfigDAO; - - private ProjectDAO projectDAO; - - private User user; - - @BeforeEach - public void setUp() { - projectDAO = new ProjectDAO(projectRepository, learnerResultRepository, testReportRepository, fileDAO, - parameterizedSymbolRepository, symbolStepRepository, symbolActionRepository, environmentDAO, - projectUrlRepository, testExecutionConfigRepository, testDAO, userDAO, environmentRepository, symbolGroupDAO, - testRepository, symbolParameterRepository, uploadableFileRepository, learnerSetupRepository, - learnerResultStepRepository, testPresenceService, symbolPresenceService, projectPresenceService, - testReportDAO, ltsFormulaSuiteDAO, ltsFormulaDAO, learnerSetupDAO, testExecutionConfigDAO); - user = new User(); - user.setId(USER_ID); - } - - @Test - public void shouldGetAllProjectsOfAnUser() { - User user = new User(); - user.setId(USER_ID); - - List projects = createProjectList(); - given(projectRepository.findAllByUser_Id(USER_ID)).willReturn(projects); - - List allProjects = projectDAO.getAll(user); - - assertEquals(projects.size(), allProjects.size()); - for (Project p : allProjects) { - assertTrue(projects.contains(p)); - } - } - - @Test - public void shouldGetAProjectByItsID() { - User user = new User(USER_ID); - Project project = new Project(); - project.addOwner(user); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - - Project p = projectDAO.getByID(user, PROJECT_ID); - - assertEquals(project, p); - } - - @Test - public void shouldThrowAnExceptionIfTheProjectCanNotFoundByID() { - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.empty()); - assertThrows(NotFoundException.class, () -> projectDAO.getByID(user, PROJECT_ID)); - } - - @Test - public void shouldUpdateAProject() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.addOwner(user); - project.setId(PROJECT_ID); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(projectRepository.save(project)).willReturn(project); - - projectDAO.update(user, PROJECT_ID, project); - - verify(projectRepository).save(project); - } - - @Test - public void shouldThrowANotFoundExceptionWhenUpdatingAUnknownProject() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.addOwner(user); - project.setId(PROJECT_ID); - - assertThrows(NotFoundException.class, () -> projectDAO.update(user, PROJECT_ID, project)); - } - - @Test - public void shouldHandleConstraintViolationExceptionOnProjectUpdateGracefully() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.addOwner(user); - project.setId(PROJECT_ID); - - given(projectRepository.save(project)).willThrow(ConstraintViolationException.class); - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - - assertThrows(ConstraintViolationException.class, () -> projectDAO.update(user, PROJECT_ID, project)); - } - - @Test - public void shouldDeleteAProject() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.addOwner(user); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - - projectDAO.delete(user, PROJECT_ID); - - verify(projectRepository).delete(project); - } - - @Test - public void shouldFailToDeleteAProjectThatDoesNotExist() { - User user = new User(); - assertThrows(NotFoundException.class, () -> projectDAO.delete(user, -1L)); - } - - - private List createProjectList() { - List projects = new ArrayList<>(); - for (int i = 0; i < TEST_PROJECT_COUNT; i++) { - Project p = new Project(); - projects.add(p); - } - return projects; - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/dao/SymbolDAOTest.java b/backend/src/test/java/de/learnlib/alex/data/dao/SymbolDAOTest.java deleted file mode 100644 index 89bd5ebd8..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/dao/SymbolDAOTest.java +++ /dev/null @@ -1,640 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.dao; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.verify; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolActionStep; -import de.learnlib.alex.data.entities.SymbolGroup; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.data.entities.actions.misc.WaitAction; -import de.learnlib.alex.data.entities.actions.web.ClearAction; -import de.learnlib.alex.data.repositories.ParameterizedSymbolRepository; -import de.learnlib.alex.data.repositories.ProjectEnvironmentRepository; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.data.repositories.SymbolActionRepository; -import de.learnlib.alex.data.repositories.SymbolGroupRepository; -import de.learnlib.alex.data.repositories.SymbolPSymbolStepRepository; -import de.learnlib.alex.data.repositories.SymbolParameterRepository; -import de.learnlib.alex.data.repositories.SymbolRepository; -import de.learnlib.alex.data.repositories.SymbolStepRepository; -import de.learnlib.alex.learning.dao.LearnerSetupDAO; -import de.learnlib.alex.testing.dao.TestDAO; -import de.learnlib.alex.testing.repositories.TestCaseStepRepository; -import de.learnlib.alex.testing.repositories.TestExecutionResultRepository; -import de.learnlib.alex.websocket.services.SymbolPresenceService; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; -import javax.persistence.RollbackException; -import javax.validation.ConstraintViolationException; -import javax.validation.ValidationException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.transaction.TransactionSystemException; - -@ExtendWith(MockitoExtension.class) -public class SymbolDAOTest { - - private static final long USER_ID = 21L; - private static final long PROJECT_ID = 42L; - private static final long GROUP_ID = 84L; - private static final long SYMBOL_ID = 168L; - - private static final int SYMBOL_LIST_SIZE = 5; - - @Mock - private ProjectRepository projectRepository; - - @Mock - private ProjectDAO projectDAO; - - @Mock - private SymbolGroupDAO symbolGroupDAO; - - @Mock - private SymbolGroupRepository symbolGroupRepository; - - @Mock - private SymbolRepository symbolRepository; - - @Mock - private SymbolActionRepository symbolActionRepository; - - @Mock - private SymbolParameterRepository symbolParameterRepository; - - @Mock - private SymbolStepRepository symbolStepRepository; - - @Mock - private ParameterizedSymbolDAO parameterizedSymbolDAO; - - @Mock - private SymbolPSymbolStepRepository symbolPSymbolStepRepository; - - @Mock - private ParameterizedSymbolRepository parameterizedSymbolRepository; - - @Mock - private TestCaseStepRepository testCaseStepRepository; - - @Mock - private TestExecutionResultRepository testExecutionResultRepository; - - @Mock - private ProjectEnvironmentRepository projectEnvironmentRepository; - - @Mock - private ObjectMapper objectMapper; - - @Mock - private SymbolParameterDAO symbolParameterDAO; - - @Mock - private SymbolPresenceService symbolPresenceService; - - @Mock - private TestDAO testDAO; - - @Mock - private LearnerSetupDAO learnerSetupDAO; - - private SymbolDAO symbolDAO; - - @BeforeEach - public void setUp() { - symbolDAO = new SymbolDAO(projectRepository, projectDAO, symbolGroupRepository, symbolRepository, - symbolActionRepository, symbolGroupDAO, symbolParameterRepository, symbolStepRepository, - parameterizedSymbolDAO, parameterizedSymbolRepository, symbolPSymbolStepRepository, - testCaseStepRepository, testExecutionResultRepository, projectEnvironmentRepository, - objectMapper, symbolParameterDAO, symbolPresenceService, testDAO, learnerSetupDAO); - } - - @Test - public void shouldCreateAValidSymbol() throws NotFoundException { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.addOwner(user); - project.setId(PROJECT_ID); - - SymbolGroup group = new SymbolGroup(); - group.setId(GROUP_ID); - - Symbol symbol = new Symbol(); - symbol.setProject(project); - symbol.setGroup(group); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(symbolGroupRepository.findById(GROUP_ID)).willReturn(Optional.of(group)); - given(symbolRepository.save(symbol)).willReturn(symbol); - - symbolDAO.create(user, PROJECT_ID, symbol); - - verify(symbolRepository).save(symbol); - } - - @Test - public void shouldFailToCreateASymbolWithADuplicateNameWithinOneSymbolGroup() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.addOwner(user); - project.setId(PROJECT_ID); - - SymbolGroup group = new SymbolGroup(); - group.setId(GROUP_ID); - - Symbol symbol = new Symbol(); - symbol.setProject(project); - symbol.setGroup(group); - symbol.setName("Test"); - - Symbol symbol2 = new Symbol(); - symbol2.setProject(project); - symbol2.setGroup(group); - symbol2.setName("Test"); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(symbolGroupRepository.findById(GROUP_ID)).willReturn(Optional.of(group)); - given(symbolRepository.findOneByGroup_IdAndName(GROUP_ID, "Test")).willReturn(symbol2); - - assertThrows(ValidationException.class, () -> symbolDAO.create(user, PROJECT_ID, symbol)); - } - - @Test - public void shouldGetAllRequestedSymbolsByIds() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.setId(PROJECT_ID); - project.addOwner(user); - - SymbolGroup group = new SymbolGroup(); - group.setId(GROUP_ID); - - List symbols = createWebSymbolTestList(project, group); - - List ids = new ArrayList<>(); - ids.add(symbols.get(0).getId()); - ids.add(symbols.get(2).getId()); - ids.add(symbols.get(3).getId()); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(symbolRepository.findAllByIdIn(ids)).willReturn(symbols); - - List symbolsFromDB = symbolDAO.getByIds(user, project.getId(), ids); - - assertEquals(symbols.size(), symbolsFromDB.size()); - for (Symbol s : symbolsFromDB) { - assertTrue(symbols.contains(s)); - } - } - - @Test - public void shouldGetNoSymbolIfIdListIsEmpty() { - User user = new User(); - Project project = new Project(); - List ids = Collections.emptyList(); - - List symbolsFromDB = symbolDAO.getByIds(user, project.getId(), ids); - - assertEquals(0, symbolsFromDB.size()); - } - - @Test - public void shouldGetAllVisibleSymbols() throws NotFoundException { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.setId(PROJECT_ID); - - SymbolGroup group = new SymbolGroup(); - group.setId(GROUP_ID); - - List symbols = createTestSymbolLists(user, project, group); - - given(symbolRepository.findAllByProject_Id(PROJECT_ID)).willReturn(symbols); - - List symbolsFromDB = symbolDAO.getAll(user, project.getId()); - - assertEquals(symbols.size(), symbolsFromDB.size()); - for (Symbol s : symbolsFromDB) { - assertTrue(symbols.contains(s)); - } - } - - @Test - public void shouldGetTheRightSymbol() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.setId(PROJECT_ID); - project.addOwner(user); - - SymbolGroup group = new SymbolGroup(); - group.setId(GROUP_ID); - - Symbol symbol = new Symbol(); - symbol.setId(SYMBOL_ID); - symbol.setProject(project); - symbol.setGroup(group); - - given(symbolRepository.findById(SYMBOL_ID)).willReturn(Optional.of(symbol)); - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - - Symbol symb2 = symbolDAO.get(user, symbol.getProjectId(), symbol.getId()); - - assertEquals(symbol, symb2); - } - - @Test - public void shouldThrowAnExceptionIfSymbolNotFound() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.setId(PROJECT_ID); - - SymbolGroup group = new SymbolGroup(); - group.setId(GROUP_ID); - - Symbol symbol = new Symbol(); - symbol.setProject(project); - symbol.setGroup(group); - - assertThrows(NotFoundException.class, () -> symbolDAO.get(user, symbol.getProjectId(), -1L)); - } - - @Test - public void shouldUpdateASymbol() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.addOwner(user); - project.setId(PROJECT_ID); - - SymbolGroup group = new SymbolGroup(); - group.setId(GROUP_ID); - - Symbol symbol = new Symbol(); - symbol.setProject(project); - symbol.setGroup(group); - symbol.setId(42L); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(symbolRepository.findById(symbol.getId())).willReturn(Optional.of(symbol)); - given(symbolRepository.save(symbol)).willReturn(symbol); - - symbolDAO.update(user, PROJECT_ID, symbol); - - verify(symbolRepository).save(symbol); - } - - @Test - public void shouldFailToUpdateASymbolsWithADuplicateNameWithinOneProject() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.addOwner(user); - project.setId(PROJECT_ID); - - SymbolGroup group = new SymbolGroup(); - group.setId(GROUP_ID); - - Symbol symbol = new Symbol(); - symbol.setId(0L); - symbol.setProject(project); - symbol.setGroup(group); - symbol.setName("Test"); - - Symbol symbol2 = new Symbol(); - symbol2.setId(1L); - symbol2.setProject(project); - symbol2.setGroup(group); - symbol2.setName("Test"); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(symbolRepository.findOneByGroup_IdAndName(GROUP_ID, "Test")).willReturn(symbol2); - - assertThrows(ValidationException.class, () -> symbolDAO.update(user, PROJECT_ID, symbol)); - } - - @Test - public void shouldHandleDataIntegrityViolationExceptionOnSymbolUpdateGracefully() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.addOwner(user); - project.setId(PROJECT_ID); - - SymbolGroup group = new SymbolGroup(); - group.setId(GROUP_ID); - - Symbol symbol = new Symbol(); - symbol.setProject(project); - symbol.setGroup(group); - symbol.setId(42L); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(symbolRepository.findById(symbol.getId())).willReturn(Optional.of(symbol)); - given(symbolRepository.save(symbol)).willThrow(DataIntegrityViolationException.class); - - assertThrows(ValidationException.class, () -> symbolDAO.update(user, PROJECT_ID, symbol)); - } - - @Test - public void shouldHandleTransactionSystemExceptionOnGroupUpdateGracefully() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.addOwner(user); - project.setId(PROJECT_ID); - - SymbolGroup group = new SymbolGroup(); - group.setId(GROUP_ID); - - Symbol symbol = new Symbol(); - symbol.setProject(project); - symbol.setGroup(group); - symbol.setId(42L); - - ConstraintViolationException constraintViolationException; - constraintViolationException = new ConstraintViolationException("Project is not valid!", new HashSet<>()); - RollbackException rollbackException = new RollbackException("RollbackException", constraintViolationException); - TransactionSystemException transactionSystemException; - transactionSystemException = new TransactionSystemException("Spring TransactionSystemException", - rollbackException); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(symbolRepository.findById(symbol.getId())).willReturn(Optional.of(symbol)); - given(symbolRepository.save(symbol)).willThrow(transactionSystemException); - - assertThrows(ValidationException.class, () -> symbolDAO.update(user, PROJECT_ID, symbol)); - } - - @Test - public void shouldMoveASymbol() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.addOwner(user); - project.setId(PROJECT_ID); - - SymbolGroup group1 = new SymbolGroup(); - group1.setId(GROUP_ID); - - SymbolGroup group2 = new SymbolGroup(); - group2.setId(GROUP_ID + 1); - - Symbol symbol = new Symbol(); - symbol.setProject(project); - symbol.setGroup(group1); - symbol.setId(SYMBOL_ID); - - List symbols = Collections.singletonList(symbol); - List symbolIds = Collections.singletonList(symbol.getId()); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(symbolRepository.findAllByIdIn(symbolIds)).willReturn(symbols); - lenient().when(symbolGroupRepository.findById(GROUP_ID)).thenReturn(Optional.of(group1)); - lenient().when(symbolGroupRepository.findById(GROUP_ID + 1)).thenReturn(Optional.of(group2)); - given(symbolRepository.saveAll(symbols)).willReturn(symbols); - - symbolDAO.move(user, PROJECT_ID, SYMBOL_ID, GROUP_ID + 1); - - assertEquals(0, group1.getSymbols().size()); - assertEquals(1, group2.getSymbols().size()); - assertEquals(group2, symbol.getGroup()); - } - - @Test - public void shouldMoveSymbols() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.setId(PROJECT_ID); - - SymbolGroup group1 = new SymbolGroup(); - group1.setId(GROUP_ID); - - SymbolGroup group2 = new SymbolGroup(); - group2.setId(GROUP_ID + 1); - - List symbols = createTestSymbolLists(user, project, group1); - List symbolIds = symbols.stream().map(Symbol::getId).collect(Collectors.toList()); - - lenient().when(symbolGroupRepository.findById(GROUP_ID)).thenReturn(Optional.of(group1)); - lenient().when(symbolGroupRepository.findById(GROUP_ID + 1)).thenReturn(Optional.of(group2)); - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(symbolRepository.findAllByIdIn(symbolIds)).willReturn(symbols); - - symbolDAO.move(user, PROJECT_ID, symbolIds, GROUP_ID + 1); - - assertEquals(0, group1.getSymbols().size()); - assertEquals(symbols.size(), group2.getSymbols().size()); - for (var symbol : symbols) { - assertEquals(group2, symbol.getGroup()); - } - } - - @Test - public void ensureThatAnExceptionIsThrownWhileMovingSymbolsIfTheGroupDoesNotExist() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.setId(PROJECT_ID); - - SymbolGroup group = new SymbolGroup(); - group.setId(GROUP_ID); - - List symbols = createTestSymbolLists(user, project, group); - List symbolIds = symbols.stream().map(Symbol::getId).collect(Collectors.toList()); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(symbolRepository.findAllByIdIn(symbolIds)).willReturn(symbols); - lenient().when(symbolGroupRepository.findById(GROUP_ID)).thenReturn(Optional.of(group)); - lenient().when(symbolGroupRepository.findById(-1L)).thenReturn(Optional.empty()); - - doThrow(NotFoundException.class).when(symbolGroupDAO).checkAccess(user, project, null); - - assertThrows(NotFoundException.class, () -> symbolDAO.move(user, PROJECT_ID, symbolIds, -1L)); - } - - @Test - public void shouldHideAValidSymbol() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.setId(PROJECT_ID); - - SymbolGroup group = new SymbolGroup(); - group.setId(GROUP_ID); - - Symbol symbol = new Symbol(); - symbol.setProject(project); - symbol.setGroup(group); - symbol.setId(42L); - - List symbols = Collections.singletonList(symbol); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(symbolRepository.findAllByIdIn(Collections.singletonList(SYMBOL_ID))).willReturn(symbols); - given(symbolRepository.saveAll(symbols)).willReturn(symbols); - - Symbol archivedSymbol = symbolDAO.hide(user, PROJECT_ID, Collections.singletonList(SYMBOL_ID)).get(0); - assertTrue(archivedSymbol.isHidden()); - } - - @Test - public void shouldNotHideAnythingByInvalidID() { - User user = new User(); - user.setId(USER_ID); - - List archivedSymbols = symbolDAO.hide(user, PROJECT_ID, Collections.singletonList(-1L)); - assertTrue(archivedSymbols.isEmpty()); - } - - @Test - public void shouldShowAValidSymbol() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.setId(PROJECT_ID); - - SymbolGroup group = new SymbolGroup(); - group.setId(GROUP_ID); - - Symbol symbol = new Symbol(); - symbol.setProject(project); - symbol.setGroup(group); - symbol.setId(SYMBOL_ID); - - given(projectDAO.getByID(user, PROJECT_ID)).willReturn(project); - given(symbolRepository.findById(SYMBOL_ID)).willReturn(Optional.of(symbol)); - - symbolDAO.hide(user, PROJECT_ID, Collections.singletonList(SYMBOL_ID)); - symbolDAO.show(user, PROJECT_ID, Collections.singletonList(SYMBOL_ID)); - - assertFalse(symbol.isHidden()); - } - - @Test - public void shouldNotShowAnythingByInvalidID() { - User user = new User(); - user.setId(USER_ID); - assertThrows(NotFoundException.class, () -> symbolDAO.show(user, PROJECT_ID, Collections.singletonList(-1L))); - } - - private List createTestSymbolLists(User user, Project project, SymbolGroup group) { - List symbols = new ArrayList<>(); - symbols.addAll(createWebSymbolTestList(project, group)); - symbols.addAll(createRESTSymbolTestList(project, group)); - - for (int id = 0; id < symbols.size(); id++) { - Symbol symbol = symbols.get(id); - long symbolId = id; - symbol.setId(symbolId); - } - - return symbols; - } - - private List createWebSymbolTestList(Project project, SymbolGroup group) { - List returnList = new ArrayList<>(); - for (int i = 0; i < SYMBOL_LIST_SIZE; i++) { - Symbol s = new Symbol(); - s.setProject(project); - project.getSymbols().add(s); - s.setId((long) i); - s.setGroup(group); - s.setName("Test Symbol - Get All Web No. " + i); - s.getSteps().add(new SymbolActionStep(new WaitAction())); - if (i == SYMBOL_LIST_SIZE - 1) { - s.setHidden(true); - } - - if (i > SYMBOL_LIST_SIZE / 2) { - s.setName(s.getName() + " 2"); - WebElementLocator node = new WebElementLocator(); - node.setSelector("#node-id"); - node.setType(WebElementLocator.Type.CSS); - - ClearAction newAction = new ClearAction(); - newAction.setNode(node); - s.getSteps().add(new SymbolActionStep(newAction)); - if (i == SYMBOL_LIST_SIZE - 1) { - s.setHidden(true); - } - } - returnList.add(s); - } - return returnList; - } - - private List createRESTSymbolTestList(Project project, SymbolGroup group) { - List returnList = new ArrayList<>(); - for (int i = 0; i < SYMBOL_LIST_SIZE; i++) { - Symbol s = new Symbol(); - s.setProject(project); - project.getSymbols().add(s); - s.setGroup(group); - s.setName("Test Symbol - Get All REST No. " + i); - - if (i > SYMBOL_LIST_SIZE / 2) { - s.setName(s.getName() + " 2"); - } - returnList.add(s); - } - return returnList; - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/dao/SymbolGroupDAOTest.java b/backend/src/test/java/de/learnlib/alex/data/dao/SymbolGroupDAOTest.java deleted file mode 100644 index 914eff5bf..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/dao/SymbolGroupDAOTest.java +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.dao; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.SymbolGroup; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.data.repositories.SymbolGroupRepository; -import de.learnlib.alex.data.repositories.SymbolRepository; -import de.learnlib.alex.websocket.services.SymbolPresenceService; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.verify; - -@ExtendWith(MockitoExtension.class) -public class SymbolGroupDAOTest { - - private static final long USER_ID = 21L; - private static final long PROJECT_ID = 42L; - private static final long GROUP_ID = 84L; - private static final long DEFAULT_GROUP_ID = 0L; - private static final int TEST_GROUP_COUNT = 3; - - @Mock - private ProjectRepository projectRepository; - - @Mock - private ProjectDAO projectDAO; - - @Mock - private SymbolGroupRepository symbolGroupRepository; - - @Mock - private SymbolRepository symbolRepository; - - @Mock - private SymbolDAO symbolDAO; - - @Mock - private SymbolPresenceService symbolPresenceService; - - private SymbolGroupDAO symbolGroupDAO; - - @BeforeEach - public void setUp() { - symbolGroupDAO = new SymbolGroupDAO(projectRepository, projectDAO, symbolGroupRepository, symbolRepository, symbolDAO, symbolPresenceService); - } - - @Test - public void shouldCreateAValidGroup() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.setId(PROJECT_ID); - project.addOwner(user); - - SymbolGroup group = new SymbolGroup(); - group.setProject(project); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(symbolGroupRepository.save(group)).willReturn(group); - - symbolGroupDAO.create(user, PROJECT_ID, group); - - verify(symbolGroupRepository).save(group); - } - - @Test - public void shouldGetAllGroupsOfAProject() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.setId(PROJECT_ID); - - List groups = createGroupsList(); - groups.forEach(g -> g.setProject(project)); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(symbolGroupRepository.findAllByProject_IdAndParent_id(PROJECT_ID, null)).willReturn(groups); - - List allGroups = symbolGroupDAO.getAll(user, PROJECT_ID); - - assertEquals(groups.size(), allGroups.size()); - for (SymbolGroup g : allGroups) { - assertTrue(groups.contains(g)); - } - } - - @Test - public void shouldThrowAnExceptionIfYouWantToGetAllGroupsOfANonExistingProject() { - User user = new User(); - user.setId(USER_ID); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.empty()); - doThrow(NotFoundException.class).when(projectDAO).checkAccess(user, null); - - assertThrows(NotFoundException.class, () -> symbolGroupDAO.getAll(user, PROJECT_ID)); - } - - @Test - public void shouldGetAGroupByItsID() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.setId(PROJECT_ID); - - SymbolGroup group = new SymbolGroup(); - group.setId(GROUP_ID); - group.setProject(project); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(symbolGroupRepository.findById(GROUP_ID)).willReturn(Optional.of(group)); - - SymbolGroup g = symbolGroupDAO.get(user, PROJECT_ID, group.getId()); - - assertEquals(group, g); - } - - @Test - public void shouldThrowAnExceptionIfTheGroupCanNotBeFound() { - User user = new User(); - user.setId(USER_ID); - - assertThrows(NotFoundException.class, () -> symbolGroupDAO.get(user, -1L, -1L)); - } - - @Test - public void shouldUpdateAGroup() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.setId(PROJECT_ID); - project.addOwner(user); - - SymbolGroup group = new SymbolGroup(); - group.setName("A group"); - group.setId(GROUP_ID); - group.setProject(project); - - SymbolGroup defaultGroup = new SymbolGroup(); - defaultGroup.setId(GROUP_ID + 1); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(symbolGroupRepository.findById(GROUP_ID)).willReturn(Optional.of(group)); - given(symbolGroupRepository.save(group)).willReturn(group); - - symbolGroupDAO.update(user, PROJECT_ID, GROUP_ID, group); - - verify(symbolGroupRepository).save(group); - } - - @Test - public void shouldDeleteAGroup() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.addOwner(user); - project.setId(PROJECT_ID); - - SymbolGroup group = new SymbolGroup(); - group.setId(GROUP_ID); - group.setProject(project); - - SymbolGroup defaultGroup = new SymbolGroup(); - defaultGroup.setId(GROUP_ID - 1L); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(symbolGroupRepository.findFirstByProject_IdOrderByIdAsc(PROJECT_ID)).willReturn(defaultGroup); - given(symbolGroupRepository.findById(GROUP_ID)).willReturn(Optional.of(group)); - - symbolGroupDAO.delete(user, PROJECT_ID, GROUP_ID); - - verify(symbolGroupRepository).delete(group); - } - - @Test - public void shouldNotDeleteTheDefaultGroupOfAProject() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.setId(PROJECT_ID); - project.addOwner(user); - - SymbolGroup group = new SymbolGroup(); - group.setId(DEFAULT_GROUP_ID); - group.setProject(project); - project.getGroups().add(group); - - given(projectRepository.findById(PROJECT_ID)).willReturn(Optional.of(project)); - given(symbolGroupRepository.findFirstByProject_IdOrderByIdAsc(PROJECT_ID)).willReturn(group); - given(symbolGroupRepository.findById(DEFAULT_GROUP_ID)).willReturn(Optional.of(group)); - - assertThrows(IllegalArgumentException.class, () -> symbolGroupDAO.delete(user, PROJECT_ID, DEFAULT_GROUP_ID)); - } - - @Test - public void shouldFailToDeleteAProjectThatDoesNotExist() { - User user = new User(); - user.setId(USER_ID); - - assertThrows(NotFoundException.class, () -> symbolGroupDAO.delete(user, PROJECT_ID, -1L)); - } - - - private List createGroupsList() { - List groups = new ArrayList<>(); - for (int i = 0; i < TEST_GROUP_COUNT; i++) { - SymbolGroup g = new SymbolGroup(); - groups.add(g); - } - return groups; - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/CounterTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/CounterTest.java deleted file mode 100644 index 33a49a54a..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/CounterTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.skyscreamer.jsonassert.JSONAssert; - -public class CounterTest { - - private static ObjectMapper om; - - private Counter c; - - @BeforeAll - public static void init() { - om = new ObjectMapper(); - } - - @BeforeEach - public void before() { - final Project project = new Project(1L); - c = new Counter(); - c.setId(1L); - c.setName("test"); - c.setValue(42); - c.setProject(project); - } - - @Test - public void shouldSerializeCounterCorrectly() throws Exception { - final String counterString = om.writeValueAsString(c); - final String expectedCounterString = "{\"id\":1,\"name\":\"test\",\"project\":1,\"value\":42}"; - JSONAssert.assertEquals(expectedCounterString, counterString, true); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/ExecuteResultTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/ExecuteResultTest.java deleted file mode 100644 index c3ad94651..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/ExecuteResultTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.Test; - -public class ExecuteResultTest { - - @Test - public void shouldGetTheDefaultSuccessOutput() { - assertEquals("Ok", new ExecuteResult().getOutput()); - assertEquals("Ok", new ExecuteResult(true).getOutput()); - } - - @Test - public void shouldGetTheCorrectSuccessOutputWithMessage() { - assertEquals("Ok (works)", new ExecuteResult(true, "works").getOutput()); - } - - @Test - public void shouldGetTheDefaultFailureOutput() { - assertEquals("Failed", new ExecuteResult(false).getOutput()); - } - - @Test - public void shouldGetTheCorrectFailureOutputWithMessage() { - assertEquals("Failed (does not work)", new ExecuteResult(false, "does not work").getOutput()); - } - - @Test - public void shouldGetTheCorrectOutputAfterSuccessNegation() { - final ExecuteResult r1 = new ExecuteResult(true); - r1.negate(); - assertEquals("Failed", r1.getOutput()); - - final ExecuteResult r2 = new ExecuteResult(true, "works"); - r2.negate(); - assertEquals("Failed (works)", r2.getOutput()); - } - - @Test - public void shouldGetTheCorrectOutputAfterFailureNegation() { - final ExecuteResult r1 = new ExecuteResult(false); - r1.negate(); - assertEquals("Ok", r1.getOutput()); - - final ExecuteResult r2 = new ExecuteResult(false, "does not work"); - r2.negate(); - assertEquals("Ok (does not work)", r2.getOutput()); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/ParameterizedSymbolTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/ParameterizedSymbolTest.java deleted file mode 100644 index f6e836645..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/ParameterizedSymbolTest.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import org.junit.jupiter.api.Test; - -public class ParameterizedSymbolTest { - - @Test - public void shouldCloneAParameterizedSymbol() { - final ParameterizedSymbol ps = createDefaultPSymbol(); - final ParameterizedSymbol copy = ps.copy(); - - assertNull(copy.getId()); - assertEquals(ps.getAlias(), copy.getAlias()); - assertEquals(ps.getSymbol(), copy.getSymbol()); - assertEquals(ps.getOutputMappings().size(), copy.getOutputMappings().size()); - copy.getOutputMappings().forEach(pv -> assertNull(pv.getId())); - assertEquals(ps.getParameterValues().size(), copy.getParameterValues().size()); - copy.getParameterValues().forEach(pv -> assertNull(pv.getId())); - } - - @Test - public void shouldGetTheComputedNameWhenNoAliasIsSpecified() { - final var ps = createDefaultPSymbol(); - assertEquals("s1" + " ", ps.getAliasOrComputedName()); - } - - @Test - public void shouldGetTheAliasAsComputedNameWhenAliasIsSpecified() { - final var ps = createDefaultPSymbol(); - final var alias = "an alias"; - ps.setAlias(alias); - assertEquals(alias, ps.getAliasOrComputedName()); - } - - @Test - public void shouldIgnoreNullParametersInComputedName() { - final SymbolInputParameter privateParam1 = new SymbolInputParameter(); - privateParam1.setName("privateString"); - privateParam1.setParameterType(SymbolParameter.ParameterType.STRING); - - final SymbolInputParameter privateParam2 = new SymbolInputParameter(); - privateParam2.setName("privateCounter"); - privateParam2.setParameterType(SymbolParameter.ParameterType.COUNTER); - - final SymbolParameterValue value1 = new SymbolParameterValue(); - value1.setValue(null); - value1.setParameter(privateParam1); - - final SymbolParameterValue value2 = new SymbolParameterValue(); - value2.setValue(null); - value2.setParameter(privateParam2); - - final ParameterizedSymbol ps = createDefaultPSymbol(); - ps.getParameterValues().addAll(Arrays.asList(value1, value2)); - - assertEquals("s1" + " ", ps.getAliasOrComputedName()); - } - - @Test - public void shouldNotDisplayArrowsInComputedNameIfParameterValuesAreEmpty() { - final ParameterizedSymbol ps = createDefaultPSymbol(); - ps.setParameterValues(new ArrayList<>()); - - assertEquals("s1", ps.getAliasOrComputedName()); - } - - private ParameterizedSymbol createDefaultPSymbol() { - final Symbol symbol = new Symbol(); - symbol.setName("s1"); - symbol.setId(0L); - - final SymbolInputParameter parameter1 = new SymbolInputParameter(); - parameter1.setSymbol(symbol); - parameter1.setId(0L); - parameter1.setName("input1"); - parameter1.setParameterType(SymbolParameter.ParameterType.STRING); - - final SymbolInputParameter parameter2 = new SymbolInputParameter(); - parameter2.setSymbol(symbol); - parameter2.setId(1L); - parameter2.setName("input2"); - parameter2.setParameterType(SymbolParameter.ParameterType.COUNTER); - - final List values = new ArrayList<>(); - - final SymbolParameterValue v1 = new SymbolParameterValue(); - v1.setValue("v1"); - v1.setId(1L); - v1.setParameter(parameter1); - values.add(v1); - - final SymbolParameterValue v2 = new SymbolParameterValue(); - v2.setValue("v2"); - v2.setId(2L); - v2.setParameter(parameter2); - values.add(v2); - - final ParameterizedSymbol ps = new ParameterizedSymbol(); - ps.setId(0L); - ps.setSymbol(symbol); - ps.setParameterValues(values); - - return ps; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/PropertyFilterMixIn.java b/backend/src/test/java/de/learnlib/alex/data/entities/PropertyFilterMixIn.java deleted file mode 100644 index d09f01706..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/PropertyFilterMixIn.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.annotation.JsonFilter; - -/** - * Helper class to filter entities on JSON serializing without adding the filter annotation to them. - */ -@JsonFilter("filter properties by name") -public class PropertyFilterMixIn { -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/SymbolActionStepTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/SymbolActionStepTest.java deleted file mode 100644 index a76a3b562..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/SymbolActionStepTest.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -import de.learnlib.alex.data.entities.actions.web.ClickAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class SymbolActionStepTest { - - private ConnectorManager connectors; - - private SymbolAction action; - - private SymbolActionStep step; - - @BeforeEach - public void setup() { - this.connectors = mock(ConnectorManager.class); - this.action = mock(ClickAction.class); - - final Symbol symbol = new Symbol(); - symbol.setProject(new Project(1L)); - - this.step = new SymbolActionStep(); - this.step.setAction(action); - this.step.setSymbol(symbol); - this.step.setNegated(false); - } - - @Test - public void shouldGetCorrectOutputOnSuccessAndNotNegated() { - given(action.executeAction(connectors)).willReturn(new ExecuteResult(true)); - final ExecuteResult r1 = step.execute(0, connectors); - - assertEquals(ExecuteResult.DEFAULT_SUCCESS_OUTPUT, r1.getOutput()); - } - - @Test - public void shouldGetCorrectOutputOnSuccessAndNegated() { - step.setNegated(true); - - given(action.executeAction(connectors)).willReturn(new ExecuteResult(true)); - final ExecuteResult r1 = step.execute(0, connectors); - - assertEquals(ExecuteResult.DEFAULT_ERROR_OUTPUT + " (1)", r1.getOutput()); - } - - @Test - public void shouldGetCorrectOutputOnFailureAndNotNegatedAndWithoutCustomMessage() { - given(action.executeAction(connectors)).willReturn(new ExecuteResult(false)); - final ExecuteResult r1 = step.execute(0, connectors); - - assertEquals(ExecuteResult.DEFAULT_ERROR_OUTPUT + " (1)", r1.getOutput()); - } - - @Test - public void shouldGetCorrectOutputOnFailureAndNotNegatedAndWithCustomMessage() { - step.setErrorOutput("button not found"); - given(action.executeAction(connectors)).willReturn(new ExecuteResult(false)); - final ExecuteResult r2 = step.execute(0, connectors); - - assertEquals(ExecuteResult.DEFAULT_ERROR_OUTPUT + " (button not found)", r2.getOutput()); - } - - @Test - public void shouldGetCorrectOutputOnFailureAndNegatedAndWithoutCustomMessage() { - step.setNegated(true); - - given(action.executeAction(connectors)).willReturn(new ExecuteResult(false)); - final ExecuteResult r1 = step.execute(0, connectors); - - assertEquals(ExecuteResult.DEFAULT_SUCCESS_OUTPUT, r1.getOutput()); - } - - @Test - public void shouldGetCorrectOutputOnFailureAndNegatedAndWithCustomMessage() { - step.setNegated(true); - - step.setErrorOutput("button not found"); - given(action.executeAction(connectors)).willReturn(new ExecuteResult(false)); - final ExecuteResult r1 = step.execute(0, connectors); - - assertEquals(ExecuteResult.DEFAULT_SUCCESS_OUTPUT + " (button not found)", r1.getOutput()); - } - - @Test - public void shouldCatchGlobalException() { - given(action.executeAction(connectors)).willThrow(IllegalStateException.class); - final ExecuteResult r1 = step.execute(0, connectors); - assertEquals(ExecuteResult.DEFAULT_ERROR_OUTPUT + " (1)", r1.getOutput()); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/SymbolPSymbolStepTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/SymbolPSymbolStepTest.java deleted file mode 100644 index 8e6c20700..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/SymbolPSymbolStepTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class SymbolPSymbolStepTest { - - private ConnectorManager connectors; - - private SymbolPSymbolStep step; - - private ParameterizedSymbol pSymbol; - - @BeforeEach - public void setup() { - this.connectors = mock(ConnectorManager.class); - this.pSymbol = mock(ParameterizedSymbol.class); - - final Symbol symbol = new Symbol(); - symbol.setProject(new Project(1L)); - - this.step = new SymbolPSymbolStep(); - this.step.setSymbol(symbol); - this.step.setPSymbol(pSymbol); - } - - @Test - public void shouldGetCorrectOutputOnSuccessAndNotNegatedAndWithoutCustomMessage() { - given(pSymbol.execute(connectors)).willReturn(new ExecuteResult(true)); - final ExecuteResult r1 = step.execute(0, connectors); - - assertEquals(ExecuteResult.DEFAULT_SUCCESS_OUTPUT, r1.getOutput()); - } - - @Test - public void shouldGetCorrectOutputOnSuccessAndNotNegatedAndWithCustomMessage() { - given(pSymbol.execute(connectors)).willReturn(new ExecuteResult(true, "login successful")); - final ExecuteResult r1 = step.execute(0, connectors); - - assertEquals(ExecuteResult.DEFAULT_SUCCESS_OUTPUT + " (login successful)", r1.getOutput()); - } - - @Test - public void shouldGetCorrectOutputOnSuccessAndNegatedAndWithoutCustomMessage() { - step.setNegated(true); - - given(pSymbol.execute(connectors)).willReturn(new ExecuteResult(true)); - final ExecuteResult r1 = step.execute(0, connectors); - - assertEquals(ExecuteResult.DEFAULT_ERROR_OUTPUT + " (1)", r1.getOutput()); - } - - @Test - public void shouldGetCorrectOutputOnSuccessAndNegatedAndWithCustomMessage() { - step.setNegated(true); - - given(pSymbol.execute(connectors)).willReturn(new ExecuteResult(true, "login successful")); - final ExecuteResult r1 = step.execute(0, connectors); - - assertEquals(ExecuteResult.DEFAULT_ERROR_OUTPUT + " (login successful)", r1.getOutput()); - } - - @Test - public void shouldGetCorrectOutputOnFailureAndNotNegated() { - given(pSymbol.execute(connectors)).willReturn(new ExecuteResult(false)); - final ExecuteResult r1 = step.execute(0, connectors); - - assertEquals(ExecuteResult.DEFAULT_ERROR_OUTPUT + " (1)", r1.getOutput()); - } - - @Test - public void shouldGetCorrectOutputOnFailureAndNegated() { - step.setNegated(true); - - given(pSymbol.execute(connectors)).willReturn(new ExecuteResult(false)); - final ExecuteResult r1 = step.execute(0, connectors); - - assertEquals(ExecuteResult.DEFAULT_SUCCESS_OUTPUT, r1.getOutput()); - } - - @Test - public void shouldCatchGlobalException() { - given(pSymbol.execute(connectors)).willThrow(IllegalStateException.class); - final ExecuteResult r1 = step.execute(0, connectors); - assertEquals(ExecuteResult.DEFAULT_ERROR_OUTPUT + " (1)", r1.getOutput()); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/SymbolParameterTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/SymbolParameterTest.java deleted file mode 100644 index 147b16cc0..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/SymbolParameterTest.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.mockito.Mockito.mock; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.dao.CounterDAO; -import de.learnlib.alex.data.entities.actions.misc.IncrementCounterAction; -import de.learnlib.alex.data.entities.actions.misc.SetCounterAction; -import de.learnlib.alex.data.entities.actions.misc.SetVariableAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.CounterStoreConnector; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import java.util.ArrayList; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class SymbolParameterTest { - - private static final Long PROJECT_ID = 1L; - - private static final String VARIABLE_NAME = "v1"; - private static final String VARIABLE_VALUE_PRE = "test"; - private static final String VARIABLE_VALUE_POST = "test2"; - - private static final String COUNTER_NAME = "c1"; - private static final Integer COUNTER_VALUE_PRE = 5; - private static final Integer COUNTER_VALUE_POST = 7; - - private ParameterizedSymbol symbol; - private ParameterizedSymbol reset; - - private ConnectorManager connectors; - - @BeforeEach - public void setUp() { - symbol = new ParameterizedSymbol(); - final Symbol s = new Symbol(); - s.setProject(new Project(PROJECT_ID)); - symbol.setSymbol(s); - - setUpReset(); - - connectors = new ConnectorManager(new ProjectEnvironment()); - CounterStoreConnector counterStore = new CounterStoreConnector(mock(CounterDAO.class), mock(User.class), mock(Project.class), new ArrayList<>()); - VariableStoreConnector variableStore = new VariableStoreConnector(); - - connectors.addConnector(counterStore); - connectors.addConnector(variableStore); - } - - private void setUpReset() { - reset = new ParameterizedSymbol(); - final Symbol r = new Symbol(); - r.setProject(new Project(PROJECT_ID)); - reset.setSymbol(r); - - SetVariableAction a1 = new SetVariableAction(); - a1.setSymbol(r); - a1.setName(VARIABLE_NAME); - a1.setValue(VARIABLE_VALUE_PRE); - r.getSteps().add(new SymbolActionStep(a1)); - - SetCounterAction a2 = new SetCounterAction(); - a2.setSymbol(r); - a2.setName(COUNTER_NAME); - a2.setValueType(SetCounterAction.ValueType.NUMBER); - a2.setValue(String.valueOf(COUNTER_VALUE_PRE)); - r.getSteps().add(new SymbolActionStep(a2)); - - SymbolOutputParameter out1 = new SymbolOutputParameter(); - out1.setSymbol(r); - out1.setName(VARIABLE_NAME); - out1.setParameterType(SymbolParameter.ParameterType.STRING); - r.getOutputs().add(out1); - - SymbolOutputParameter out2 = new SymbolOutputParameter(); - out2.setSymbol(r); - out2.setName(COUNTER_NAME); - out2.setParameterType(SymbolParameter.ParameterType.COUNTER); - r.getOutputs().add(out2); - } - - @Test - public void shouldNotModifyTheGlobalCounterStoreIfNoOutputIsDefined() { - SymbolInputParameter inParam = new SymbolInputParameter(); - inParam.setName(COUNTER_NAME); - inParam.setParameterType(SymbolParameter.ParameterType.COUNTER); - symbol.getSymbol().getInputs().add(inParam); - - IncrementCounterAction action = new IncrementCounterAction(); - action.setIncrementBy(2); - action.setName(COUNTER_NAME); - action.setSymbol(symbol.getSymbol()); - symbol.getSymbol().getSteps().add(new SymbolActionStep(action)); - - reset.execute(connectors); - symbol.execute(connectors); - - assertEquals(connectors.getConnector(CounterStoreConnector.class).get(COUNTER_NAME), COUNTER_VALUE_PRE); - } - - @Test - public void shouldModifyTheGlobalCounterStoreIfOutputIsDefined() { - SymbolInputParameter inParam = new SymbolInputParameter(); - inParam.setName(COUNTER_NAME); - inParam.setParameterType(SymbolParameter.ParameterType.COUNTER); - symbol.getSymbol().getInputs().add(inParam); - - IncrementCounterAction action = new IncrementCounterAction(); - action.setIncrementBy(2); - action.setName(COUNTER_NAME); - action.setSymbol(symbol.getSymbol()); - symbol.getSymbol().getSteps().add(new SymbolActionStep(action)); - - SymbolOutputParameter outParam = new SymbolOutputParameter(); - outParam.setName(COUNTER_NAME); - outParam.setParameterType(SymbolParameter.ParameterType.COUNTER); - symbol.getSymbol().getOutputs().add(outParam); - - reset.execute(connectors); - symbol.execute(connectors); - - assertEquals(connectors.getConnector(CounterStoreConnector.class).get(COUNTER_NAME), COUNTER_VALUE_POST); - } - - @Test - public void shouldNotModifyTheGlobalVariableStoreIfNoOutputIsDefined() { - SymbolInputParameter inParam = new SymbolInputParameter(); - inParam.setName(VARIABLE_NAME); - inParam.setParameterType(SymbolParameter.ParameterType.STRING); - symbol.getSymbol().getInputs().add(inParam); - - SetVariableAction action = new SetVariableAction(); - action.setSymbol(symbol.getSymbol()); - action.setName(VARIABLE_NAME); - action.setValue(VARIABLE_VALUE_POST); - symbol.getSymbol().getSteps().add(new SymbolActionStep(action)); - - reset.execute(connectors); - symbol.execute(connectors); - - assertEquals(connectors.getConnector(VariableStoreConnector.class).get(VARIABLE_NAME), VARIABLE_VALUE_PRE); - } - - @Test - public void shouldModifyTheGlobalVariableStoreIfOutputIsDefined() { - SymbolInputParameter inParam = new SymbolInputParameter(); - inParam.setName(VARIABLE_NAME); - inParam.setParameterType(SymbolParameter.ParameterType.STRING); - symbol.getSymbol().getInputs().add(inParam); - - SymbolOutputParameter outParam = new SymbolOutputParameter(); - outParam.setName(VARIABLE_NAME); - outParam.setParameterType(SymbolParameter.ParameterType.STRING); - symbol.getSymbol().getOutputs().add(outParam); - - SetVariableAction action = new SetVariableAction(); - action.setSymbol(symbol.getSymbol()); - action.setName(VARIABLE_NAME); - action.setValue(VARIABLE_VALUE_POST); - symbol.getSymbol().getSteps().add(new SymbolActionStep(action)); - - reset.execute(connectors); - symbol.execute(connectors); - - assertEquals(connectors.getConnector(VariableStoreConnector.class).get(VARIABLE_NAME), VARIABLE_VALUE_POST); - } - - @Test - public void shouldFailIfUndefinedCounterIsSpecifiedAsInput() { - SymbolInputParameter inParam = new SymbolInputParameter(); - inParam.setName("undefined"); - inParam.setParameterType(SymbolParameter.ParameterType.COUNTER); - symbol.getSymbol().getInputs().add(inParam); - - reset.execute(connectors); - ExecuteResult result = symbol.execute(connectors); - - assertFalse(result.isSuccess()); - } - - @Test - public void shouldFailIfUndefinedVariableIsSpecifiedAsInput() { - SymbolInputParameter inParam = new SymbolInputParameter(); - inParam.setName("undefined"); - inParam.setParameterType(SymbolParameter.ParameterType.STRING); - symbol.getSymbol().getInputs().add(inParam); - - reset.execute(connectors); - ExecuteResult result = symbol.execute(connectors); - - assertFalse(result.isSuccess()); - } - - @Test - public void shouldFailIfUndefinedCounterIsSpecifiedAsOutput() { - SymbolOutputParameter outParam = new SymbolOutputParameter(); - outParam.setName("undefined"); - outParam.setParameterType(SymbolParameter.ParameterType.COUNTER); - symbol.getSymbol().getOutputs().add(outParam); - - reset.execute(connectors); - ExecuteResult result = symbol.execute(connectors); - - assertFalse(result.isSuccess()); - } - - @Test - public void shouldFailIfUndefinedVariableIsSpecifiedAsOutput() { - SymbolOutputParameter outParam = new SymbolOutputParameter(); - outParam.setName("undefined"); - outParam.setParameterType(SymbolParameter.ParameterType.STRING); - symbol.getSymbol().getOutputs().add(outParam); - - reset.execute(connectors); - ExecuteResult result = symbol.execute(connectors); - - assertFalse(result.isSuccess()); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/SymbolTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/SymbolTest.java deleted file mode 100644 index 434e1c917..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/SymbolTest.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.mock; - -import de.learnlib.alex.data.entities.actions.web.CheckTextWebAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.CounterStoreConnector; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; -import org.openqa.selenium.WebDriver; - -@ExtendWith(MockitoExtension.class) -public class SymbolTest { - - private static final Long PROJECT_ID = 1L; - - private WebSiteConnector webSiteConnector; - private ConnectorManager connectorManager; - - private Symbol symbol; - - private CheckTextWebAction a1; - - private SymbolActionStep actionStep; - private SymbolPSymbolStep symbolStep; - - private ParameterizedSymbol pSymbol; - - @BeforeEach - public void setUp() { - symbol = new Symbol(); - symbol.setProject(new Project(PROJECT_ID)); - - a1 = new CheckTextWebAction(); - a1.setRegexp(false); - a1.setValue("test"); - a1.setSymbol(symbol); - - actionStep = new SymbolActionStep(a1); - actionStep.setSymbol(symbol); - - final Symbol s = new Symbol(); - s.setProject(new Project(PROJECT_ID)); - s.getSteps().add(new SymbolActionStep(a1)); - - pSymbol = new ParameterizedSymbol(); - pSymbol.setSymbol(s); - - symbolStep = new SymbolPSymbolStep(); - symbolStep.setSymbol(symbol); - symbolStep.setPSymbol(pSymbol); - - symbol.getSteps().add(actionStep); - symbol.getSteps().add(symbolStep); - - connectorManager = mock(ConnectorManager.class); - webSiteConnector = mock(WebSiteConnector.class); - - lenient().when(connectorManager.getConnector(WebSiteConnector.class)).thenReturn(webSiteConnector); - lenient().when(connectorManager.getConnector(VariableStoreConnector.class)).thenReturn(mock(VariableStoreConnector.class)); - lenient().when(connectorManager.getConnector(CounterStoreConnector.class)).thenReturn(mock(CounterStoreConnector.class)); - given(webSiteConnector.getDriver()).willReturn(mock(WebDriver.class)); - } - - @Test - public void shouldReturnOkOnSuccessAndNoCustomOutput() { - given(webSiteConnector.getDriver().getPageSource()).willReturn("test"); - - ExecuteResult result = symbol.execute(connectorManager); - - assertTrue(result.isSuccess()); - assertEquals(result.getOutput(), ExecuteResult.DEFAULT_SUCCESS_OUTPUT); - } - - @Test - public void shouldReturnACustomOutputOnSuccess() { - given(webSiteConnector.getDriver().getPageSource()).willReturn("test"); - - symbol.setSuccessOutput("success"); - ExecuteResult result = symbol.execute(connectorManager); - - assertTrue(result.isSuccess()); - assertEquals(ExecuteResult.DEFAULT_SUCCESS_OUTPUT + " (success)", result.getOutput()); - } - - @Test - public void shouldReturnFailedOnErrorAndNoCustomOutput() { - given(webSiteConnector.getDriver().getPageSource()).willReturn("something"); - - ExecuteResult result = symbol.execute(connectorManager); - - assertFalse(result.isSuccess()); - assertEquals(ExecuteResult.DEFAULT_ERROR_OUTPUT + " (1)", result.getOutput()); - } - - @Test - public void shouldReturnFailedOnErrorAndCustomOutput() { - actionStep.setErrorOutput("not found"); - given(webSiteConnector.getDriver().getPageSource()).willReturn("something"); - - ExecuteResult result = symbol.execute(connectorManager); - - assertFalse(result.isSuccess()); - assertEquals(ExecuteResult.DEFAULT_ERROR_OUTPUT + " (not found)", result.getOutput()); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/UploadableFileTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/UploadableFileTest.java deleted file mode 100644 index 5e056fae6..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/UploadableFileTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.skyscreamer.jsonassert.JSONAssert; - -public class UploadableFileTest { - - private static ObjectMapper om; - - @BeforeAll - public static void setup() { - om = new ObjectMapper(); - } - - @Test - public void shouldSerializeCorrectly() throws Exception { - final UploadableFile file = new UploadableFile(); - file.setName("test"); - file.setProjectId(1L); - file.setId(1L); - - final String fileString = om.writeValueAsString(file); - final String expectedFileString = "{\"id\":1,\"name\":\"test\",\"project\":1}"; - JSONAssert.assertEquals(expectedFileString, fileString, true); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/CredentialsTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/CredentialsTest.java deleted file mode 100644 index 342d912d4..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/CredentialsTest.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.Test; - -public class CredentialsTest { - - @Test - public void shouldCreateCorrectBase64() { - final var credentials = new Credentials("alex", "alex"); - - assertEquals("YWxleDphbGV4", credentials.toBase64()); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/AssertCounterActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/AssertCounterActionTest.java deleted file mode 100644 index e2de8b01a..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/AssertCounterActionTest.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.CounterStoreConnector; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class AssertCounterActionTest { - - private static final String TEST_NAME = "counter"; - private static final Integer TEST_VALUE = 42; - - private AssertCounterAction assertAction; - - @BeforeEach - public void setUp() { - assertAction = new AssertCounterAction(); - assertAction.setName(TEST_NAME); - assertAction.setValue(TEST_VALUE); - assertAction.setOperator(AssertCounterAction.Operator.EQUAL); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(assertAction); - AssertCounterAction assertAction2 = (AssertCounterAction) mapper.readValue(json, SymbolAction.class); - - assertEquals(assertAction.getName(), assertAction2.getName()); - assertEquals(assertAction.getValue(), assertAction2.getValue()); - assertEquals(assertAction.getOperator(), assertAction2.getOperator()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - File file = new File(getClass().getResource("/actions/StoreSymbolActions/AssertCounterTestData.json").toURI()); - SymbolAction obj = mapper.readValue(file, SymbolAction.class); - - assertTrue(obj instanceof AssertCounterAction); - AssertCounterAction objAsAction = (AssertCounterAction) obj; - assertEquals(TEST_NAME, objAsAction.getName()); - assertEquals(TEST_VALUE, objAsAction.getValue()); - assertEquals(AssertCounterAction.Operator.EQUAL, objAsAction.getOperator()); - } - - @ParameterizedTest(name = "use counter value: \"{0}\", success: \"{1}\" for the test") - @CsvSource({ - "41, true", - "42, false", - "43, false", - }) - public void ensureThatLessWorks(int value, boolean success) { - ensureThatOperatorWorks(AssertCounterAction.Operator.LESS_THAN, value, success); - } - - @ParameterizedTest(name = "use counter value: \"{0}\", success: \"{1}\" for the test") - @CsvSource({ - "41, true", - "42, true", - "43, false", - }) - public void ensureThatLessOrEqualsWorks(int value, boolean success) { - ensureThatOperatorWorks(AssertCounterAction.Operator.LESS_OR_EQUAL, value, success); - } - - @ParameterizedTest(name = "use counter value: \"{0}\", success: \"{1}\" for the test") - @CsvSource({ - "41, false", - "42, true", - "43, false", - }) - public void ensureThatEqualsWorks(int value, boolean success) { - ensureThatOperatorWorks(AssertCounterAction.Operator.EQUAL, value, success); - } - - @ParameterizedTest(name = "use counter value: \"{0}\", success: \"{1}\" for the test") - @CsvSource({ - "41, false", - "42, true", - "43, true", - }) - public void ensureThatGreaterOrEqualsWorks(int value, boolean success) { - ensureThatOperatorWorks(AssertCounterAction.Operator.GREATER_OR_EQUAL, value, success); - } - - @ParameterizedTest(name = "use counter value: \"{0}\", success: \"{1}\" for the test") - @CsvSource({ - "41, false", - "42, false", - "43, true", - }) - public void ensureThatGreaterWorks(int value, boolean success) { - ensureThatOperatorWorks(AssertCounterAction.Operator.GREATER_THAN, value, success); - } - - private void ensureThatOperatorWorks(AssertCounterAction.Operator operator, int value, boolean success) { - CounterStoreConnector counters = mock(CounterStoreConnector.class); - - ConnectorManager connector = mock(ConnectorManager.class); - given(connector.getConnector(CounterStoreConnector.class)).willReturn(counters); - - assertAction.setOperator(operator); - - given(counters.get(TEST_NAME)).willReturn(value); - ExecuteResult result = assertAction.execute(connector); - assertEquals(success, result.isSuccess()); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/AssertVariableActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/AssertVariableActionTest.java deleted file mode 100644 index b9a27483b..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/AssertVariableActionTest.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class AssertVariableActionTest { - - private static final String TEST_VALUE = "foobar"; - private static final String TEST_NAME = "variable"; - - private AssertVariableAction assertAction; - - @BeforeEach - public void setUp() { - final Symbol symbol = new Symbol(); - symbol.setProject(new Project(1L)); - - assertAction = new AssertVariableAction(); - assertAction.setName(TEST_NAME); - assertAction.setValue(TEST_VALUE); - assertAction.setRegexp(false); - assertAction.setSymbol(symbol); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(assertAction); - AssertVariableAction assertAction2 = (AssertVariableAction) mapper.readValue(json, SymbolAction.class); - - assertEquals(assertAction.getName(), assertAction2.getName()); - assertEquals(assertAction.getValue(), assertAction2.getValue()); - assertEquals(assertAction.isRegexp(), assertAction2.isRegexp()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - File file = new File(getClass().getResource("/actions/StoreSymbolActions/AssertVariableTestData.json").toURI()); - SymbolAction obj = mapper.readValue(file, SymbolAction.class); - - assertTrue(obj instanceof AssertVariableAction); - AssertVariableAction objAsAction = (AssertVariableAction) obj; - assertEquals(TEST_NAME, objAsAction.getName()); - assertEquals(TEST_VALUE, objAsAction.getValue()); - assertTrue(objAsAction.isRegexp()); - } - - @Test - public void ensureThatAssertingWithoutRegexWorks() { - VariableStoreConnector variables = mock(VariableStoreConnector.class); - ConnectorManager connector = mock(ConnectorManager.class); - given(connector.getConnector(VariableStoreConnector.class)).willReturn(variables); - - // OK - given(variables.get(TEST_NAME)).willReturn(TEST_VALUE); - ExecuteResult result = assertAction.executeAction(connector); - assertTrue(result.isSuccess()); - - // not OK - given(variables.get(TEST_NAME)).willReturn(TEST_VALUE + " - invalid"); - result = assertAction.executeAction(connector); - assertFalse(result.isSuccess()); - } - - - @Test - public void ensureThatAssertingWithRegexWorks() { - VariableStoreConnector variables = mock(VariableStoreConnector.class); - ConnectorManager connector = mock(ConnectorManager.class); - given(connector.getConnector(VariableStoreConnector.class)).willReturn(variables); - assertAction.setRegexp(true); - assertAction.setValue("f[o]+bar"); - - // OK - given(variables.get(TEST_NAME)).willReturn(TEST_VALUE); - ExecuteResult result = assertAction.executeAction(connector); - assertTrue(result.isSuccess()); - - // not OK - given(variables.get(TEST_NAME)).willReturn(TEST_VALUE + " - invalid"); - result = assertAction.executeAction(connector); - assertFalse(result.isSuccess()); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/IncrementCounterActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/IncrementCounterActionTest.java deleted file mode 100644 index 56abd5cc7..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/IncrementCounterActionTest.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.CounterStoreConnector; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class IncrementCounterActionTest { - - private static final Long USER_ID = 3L; - private static final Long PROJECT_ID = 10L; - private static final String TEST_NAME = "counter"; - - private IncrementCounterAction incrementAction; - - @BeforeEach - public void setUp() { - User user = new User(); - user.setId(USER_ID); - - Project project = new Project(); - project.addOwner(user); - project.setId(PROJECT_ID); - - Symbol symbol = new Symbol(); - symbol.setProject(project); - - incrementAction = new IncrementCounterAction(); - incrementAction.setSymbol(symbol); - incrementAction.setName(TEST_NAME); - incrementAction.setIncrementBy(1); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(incrementAction); - IncrementCounterAction declareAction2 = (IncrementCounterAction) mapper.readValue(json, SymbolAction.class); - - assertEquals(incrementAction.getName(), declareAction2.getName()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - URI uri = getClass().getResource("/actions/StoreSymbolActions/IncrementCounterTestData.json").toURI(); - File file = new File(uri); - SymbolAction obj = mapper.readValue(file, SymbolAction.class); - - assertTrue(obj instanceof IncrementCounterAction); - IncrementCounterAction objAsAction = (IncrementCounterAction) obj; - assertEquals(TEST_NAME, objAsAction.getName()); - } - - @Test - public void shouldSuccessfullyIncrementCounter() { - CounterStoreConnector counters = mock(CounterStoreConnector.class); - - ConnectorManager connector = mock(ConnectorManager.class); - given(connector.getConnector(CounterStoreConnector.class)).willReturn(counters); - - ExecuteResult result = incrementAction.execute(connector); - - assertTrue(result.isSuccess()); - verify(counters).incrementBy(PROJECT_ID, TEST_NAME, 1); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetCounterActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetCounterActionTest.java deleted file mode 100644 index c2b3111a3..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetCounterActionTest.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.CounterStoreConnector; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class SetCounterActionTest { - - private static final Long PROJECT_ID = 10L; - private static final String TEST_NAME = "counter"; - private static final String TEST_VALUE = "42"; - - private SetCounterAction setAction; - - @BeforeEach - public void setUp() { - Project project = new Project(); - project.setId(PROJECT_ID); - - Symbol symbol = new Symbol(); - symbol.setProject(project); - - setAction = new SetCounterAction(); - setAction.setSymbol(symbol); - setAction.setName(TEST_NAME); - setAction.setValue(TEST_VALUE); - setAction.setValueType(SetCounterAction.ValueType.NUMBER); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(setAction); - SetCounterAction declareAction2 = (SetCounterAction) mapper.readValue(json, SymbolAction.class); - - assertEquals(setAction.getName(), declareAction2.getName()); - assertEquals(setAction.getValue(), declareAction2.getValue()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - File file = new File(getClass().getResource("/actions/StoreSymbolActions/SetCounterTestData.json").toURI()); - SymbolAction obj = mapper.readValue(file, SymbolAction.class); - - assertTrue(obj instanceof SetCounterAction); - SetCounterAction objAsAction = (SetCounterAction) obj; - assertEquals(TEST_NAME, objAsAction.getName()); - assertEquals(TEST_VALUE, objAsAction.getValue()); - } - - @Test - public void shouldSuccessfulSetTheCounterValue() { - CounterStoreConnector counters = mock(CounterStoreConnector.class); - - ConnectorManager connector = mock(ConnectorManager.class); - given(connector.getConnector(CounterStoreConnector.class)).willReturn(counters); - - ExecuteResult result = setAction.execute(connector); - - assertTrue(result.isSuccess()); - verify(counters).set(PROJECT_ID, TEST_NAME, Integer.parseInt(TEST_VALUE)); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableActionTest.java deleted file mode 100644 index dd3abc47c..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableActionTest.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.CounterStoreConnector; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class SetVariableActionTest { - - private static final String PROJECT_URL = "http://localhost:8000/"; - - private static final String TEST_VALUE = "foobar"; - private static final String TEST_NAME = "variable"; - - private SetVariableAction setAction; - - @BeforeEach - public void setUp() { - Symbol symbol = new Symbol(); - - setAction = new SetVariableAction(); - setAction.setSymbol(symbol); - setAction.setName(TEST_NAME); - setAction.setValue(TEST_VALUE); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(setAction); - SetVariableAction declareAction2 = (SetVariableAction) mapper.readValue(json, SymbolAction.class); - - assertEquals(setAction.getName(), declareAction2.getName()); - assertEquals(setAction.getValue(), declareAction2.getValue()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - File file = new File(getClass().getResource("/actions/StoreSymbolActions/SetVariableTestData.json").toURI()); - SymbolAction obj = mapper.readValue(file, SymbolAction.class); - - assertTrue(obj instanceof SetVariableAction); - SetVariableAction objAsAction = (SetVariableAction) obj; - assertEquals(TEST_NAME, objAsAction.getName()); - assertEquals(TEST_VALUE, objAsAction.getValue()); - } - - @Test - public void shouldSuccessfulSetTheVariableValue() { - VariableStoreConnector variables = mock(VariableStoreConnector.class); - ConnectorManager connector = mock(ConnectorManager.class); - given(connector.getConnector(VariableStoreConnector.class)).willReturn(variables); - - ExecuteResult result = setAction.executeAction(connector); - - assertTrue(result.isSuccess()); - verify(variables).set(TEST_NAME, TEST_VALUE); - } - - @Test - public void shouldSuccessfulSetTheVariableValueWithCounter() { - CounterStoreConnector counters = mock(CounterStoreConnector.class); - given(counters.get("counter")).willReturn(2); - - WebSiteConnector webSiteConnector = mock(WebSiteConnector.class); - VariableStoreConnector variables = mock(VariableStoreConnector.class); - - ConnectorManager connector = mock(ConnectorManager.class); - given(connector.getConnector(WebSiteConnector.class)).willReturn(webSiteConnector); - given(connector.getConnector(CounterStoreConnector.class)).willReturn(counters); - given(connector.getConnector(VariableStoreConnector.class)).willReturn(variables); - - setAction.setValue(TEST_VALUE + "{{#counter}}"); - - ExecuteResult result = setAction.executeAction(connector); - - assertTrue(result.isSuccess()); - verify(variables).set(TEST_NAME, TEST_VALUE + "2"); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByCookieActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByCookieActionTest.java deleted file mode 100644 index 4c723be21..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByCookieActionTest.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebServiceConnector; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Map; -import javax.ws.rs.core.NewCookie; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.openqa.selenium.Cookie; -import org.openqa.selenium.WebDriver; - -public class SetVariableByCookieActionTest { - - private static final String VARIABLE_NAME = "foobar"; - - private static final String COOKIE_NAME = "cookie"; - private static final String COOKIE_VALUE = "hello world"; - - private SetVariableByCookieAction setAction; - - @BeforeEach - public void setUp() { - setAction = new SetVariableByCookieAction(); - setAction.setName(VARIABLE_NAME); - setAction.setValue(COOKIE_NAME); - setAction.setCookieType(SetVariableByCookieAction.CookieType.WEB); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(setAction); - SetVariableByCookieAction setAction2 = mapper.readValue(json, SetVariableByCookieAction.class); - - assertEquals(setAction.getName(), setAction2.getName()); - assertEquals(setAction.getValue(), setAction2.getValue()); - assertEquals(setAction.getCookieType(), setAction2.getCookieType()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - URI uri = getClass().getResource("/actions/StoreSymbolActions/SetVariableByCookieTestData.json").toURI(); - File file = new File(uri); - SymbolAction obj = mapper.readValue(file, SymbolAction.class); - - assertTrue(obj instanceof SetVariableByCookieAction); - SetVariableByCookieAction objAsAction = (SetVariableByCookieAction) obj; - assertEquals(VARIABLE_NAME, objAsAction.getName()); - assertEquals(COOKIE_NAME, objAsAction.getValue()); - assertEquals(SetVariableByCookieAction.CookieType.WEB, objAsAction.getCookieType()); - } - - @Test - public void shouldSetTheVariableFromAnExistingWebCookie() { - ConnectorManager connector = mock(ConnectorManager.class); - VariableStoreConnector variables = mock(VariableStoreConnector.class); - given(connector.getConnector(VariableStoreConnector.class)).willReturn(variables); - Cookie cookie = mock(Cookie.class); - given(cookie.getValue()).willReturn(COOKIE_VALUE); - WebSiteConnector webSiteConnector = createWebSiteConnectorMock(cookie); - given(connector.getConnector(WebSiteConnector.class)).willReturn(webSiteConnector); - - setAction.execute(connector); - - verify(variables).set(VARIABLE_NAME, COOKIE_VALUE); - } - - @Test - public void shouldReturnFailedIfTheWebCookiesDoesNotExists() { - ConnectorManager connector = mock(ConnectorManager.class); - VariableStoreConnector variables = mock(VariableStoreConnector.class); - given(connector.getConnector(VariableStoreConnector.class)).willReturn(variables); - WebSiteConnector webSiteConnector = createWebSiteConnectorMock(null); - given(connector.getConnector(WebSiteConnector.class)).willReturn(webSiteConnector); - - setAction.execute(connector); - - verify(variables, never()).set(eq(VARIABLE_NAME), anyString()); - } - - private WebSiteConnector createWebSiteConnectorMock(Cookie cookie) { - WebDriver.Options options = mock(WebDriver.Options.class); - given(options.getCookieNamed(COOKIE_NAME)).willReturn(cookie); - WebDriver driver = mock(WebDriver.class); - given(driver.manage()).willReturn(options); - WebSiteConnector webSiteConnector = mock(WebSiteConnector.class); - given(webSiteConnector.getDriver()).willReturn(driver); - return webSiteConnector; - } - - @Test - public void shouldSetTheVariableFromAnExistingRESTCookie() { - ConnectorManager connector = mock(ConnectorManager.class); - VariableStoreConnector variables = mock(VariableStoreConnector.class); - given(connector.getConnector(VariableStoreConnector.class)).willReturn(variables); - NewCookie cookie = mock(NewCookie.class); - given(cookie.getValue()).willReturn(COOKIE_VALUE); - WebServiceConnector webServiceConnector = createWebServiceConnectorMock(cookie); - given(connector.getConnector(WebServiceConnector.class)).willReturn(webServiceConnector); - setAction.setCookieType(SetVariableByCookieAction.CookieType.REST); - - setAction.execute(connector); - - verify(variables).set(VARIABLE_NAME, COOKIE_VALUE); - } - - @Test - public void shouldReturnFailedIfTheRESTCookiesDoesNotExists() { - ConnectorManager connector = mock(ConnectorManager.class); - VariableStoreConnector variables = mock(VariableStoreConnector.class); - given(connector.getConnector(VariableStoreConnector.class)).willReturn(variables); - WebServiceConnector webServiceConnector = createWebServiceConnectorMock(null); - given(connector.getConnector(WebServiceConnector.class)).willReturn(webServiceConnector); - setAction.setCookieType(SetVariableByCookieAction.CookieType.REST); - - setAction.execute(connector); - - verify(variables, never()).set(eq(VARIABLE_NAME), anyString()); - - } - - private WebServiceConnector createWebServiceConnectorMock(NewCookie cookie) { - Map cookies = mock(Map.class); - given(cookies.get(COOKIE_NAME)).willReturn(cookie); - WebServiceConnector webServiceConnector = mock(WebServiceConnector.class); - given(webServiceConnector.getCookies()).willReturn(cookies); - return webServiceConnector; - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByHTMLElementActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByHTMLElementActionTest.java deleted file mode 100644 index 8d47cc936..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByHTMLElementActionTest.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; - -public class SetVariableByHTMLElementActionTest { - - private static final String VARIABLE = "variable"; - private static final String NODE_NAME = "foobar"; - private static final String NODE_VALUE = "Hello World"; - - private SetVariableByHTMLElementAction setAction; - - private WebElementLocator node; - - @BeforeEach - public void setUp() { - node = new WebElementLocator(); - node.setSelector(NODE_NAME); - node.setType(WebElementLocator.Type.CSS); - - Symbol symbol = new Symbol(); - symbol.setProject(new Project(1L)); - - setAction = new SetVariableByHTMLElementAction(); - setAction.setSymbol(symbol); - setAction.setName(VARIABLE); - setAction.setNode(node); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(setAction); - SetVariableByHTMLElementAction declareAction2 = mapper.readValue(json, SetVariableByHTMLElementAction.class); - - assertEquals(setAction.getName(), declareAction2.getName()); - assertEquals(setAction.getNode(), declareAction2.getNode()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - URI uri = getClass().getResource("/actions/StoreSymbolActions/SetVariableByHTMLElementTestData.json").toURI(); - File file = new File(uri); - SymbolAction obj = mapper.readValue(file, SymbolAction.class); - - assertTrue(obj instanceof SetVariableByHTMLElementAction); - SetVariableByHTMLElementAction objAsAction = (SetVariableByHTMLElementAction) obj; - assertEquals(VARIABLE, objAsAction.getName()); - assertEquals(node, objAsAction.getNode()); - } - - @Test - public void shouldSetTheVariableIfTheNodeExists() { - ConnectorManager connector = mock(ConnectorManager.class); - VariableStoreConnector variables = mock(VariableStoreConnector.class); - given(connector.getConnector(VariableStoreConnector.class)).willReturn(variables); - - WebElement element = mock(WebElement.class); - given(element.getText()).willReturn(NODE_VALUE); - WebSiteConnector webSiteConnector = mock(WebSiteConnector.class); - given(webSiteConnector.getElement(node)).willReturn(element); - given(connector.getConnector(WebSiteConnector.class)).willReturn(webSiteConnector); - - ExecuteResult result = setAction.executeAction(connector); - - assertTrue(result.isSuccess()); - verify(variables).set(VARIABLE, NODE_VALUE); - } - - @Test - public void shouldReturnFailedIfTheNodeDoesNotExists() { - ConnectorManager connector = mock(ConnectorManager.class); - VariableStoreConnector variables = mock(VariableStoreConnector.class); - given(connector.getConnector(VariableStoreConnector.class)).willReturn(variables); - - WebSiteConnector webSiteConnector = mock(WebSiteConnector.class); - given(webSiteConnector.getElement(node)).willThrow(NoSuchElementException.class); - given(connector.getConnector(WebSiteConnector.class)).willReturn(webSiteConnector); - - ExecuteResult result = setAction.executeAction(connector); - - assertFalse(result.isSuccess()); - verify(variables, never()).set(eq(VARIABLE), anyString()); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByHttpResponseActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByHttpResponseActionTest.java deleted file mode 100644 index 36048df96..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByHttpResponseActionTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebServiceConnector; -import javax.validation.ValidationException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -public class SetVariableByHttpResponseActionTest { - - private SetVariableByHttpResponseAction action; - - private ConnectorManager connectors; - - private WebServiceConnector webServiceConnector; - - private VariableStoreConnector variableStore; - - @BeforeEach - public void before() { - this.webServiceConnector = Mockito.mock(WebServiceConnector.class); - this.variableStore = new VariableStoreConnector(); - - this.connectors = Mockito.mock(ConnectorManager.class); - Mockito.when(connectors.getConnector(WebServiceConnector.class)).thenReturn(this.webServiceConnector); - Mockito.when(connectors.getConnector(VariableStoreConnector.class)).thenReturn(this.variableStore); - - this.action = new SetVariableByHttpResponseAction(); - this.action.setName("var"); - } - - @Test - public void shouldSaveResponseBodyInVariable() { - Mockito.when(webServiceConnector.getBody()).thenReturn("testBody"); - - final ExecuteResult result = action.execute(connectors); - - assertTrue(result.isSuccess()); - assertEquals("testBody", variableStore.get("var")); - } - - @Test - public void shouldNotSaveResponseBodyInVariable() { - Mockito.when(webServiceConnector.getBody()).thenThrow(new ValidationException()); - - final ExecuteResult result = action.execute(connectors); - - assertFalse(result.isSuccess()); - assertNull(variableStore.getStore().get("var")); - assertThrows(IllegalStateException.class, () -> variableStore.get("var")); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByHttpStatusActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByHttpStatusActionTest.java deleted file mode 100644 index 828c76890..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByHttpStatusActionTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebServiceConnector; -import javax.validation.ValidationException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -public class SetVariableByHttpStatusActionTest { - - private SetVariableByHttpStatusAction action; - - private ConnectorManager connectors; - - private WebServiceConnector webServiceConnector; - - private VariableStoreConnector variableStore; - - @BeforeEach - public void before() { - this.webServiceConnector = Mockito.mock(WebServiceConnector.class); - this.variableStore = new VariableStoreConnector(); - - this.connectors = Mockito.mock(ConnectorManager.class); - Mockito.when(connectors.getConnector(WebServiceConnector.class)).thenReturn(this.webServiceConnector); - Mockito.when(connectors.getConnector(VariableStoreConnector.class)).thenReturn(this.variableStore); - - this.action = new SetVariableByHttpStatusAction(); - this.action.setName("var"); - } - - @Test - public void shouldStoreStatusInAVariable() { - Mockito.when(webServiceConnector.getStatus()).thenReturn(200); - - final ExecuteResult result = this.action.execute(connectors); - - assertTrue(result.isSuccess()); - assertEquals("200", variableStore.get("var")); - } - - @Test - public void shouldNotStoreStatusIfAnExceptionOccurs() { - Mockito.when(webServiceConnector.getStatus()).thenThrow(new ValidationException()); - - final ExecuteResult result = this.action.execute(connectors); - - assertFalse(result.isSuccess()); - assertNull(variableStore.getStore().get("var")); - assertThrows(IllegalStateException.class, () -> variableStore.get("var")); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByJSONAttributeActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByJSONAttributeActionTest.java deleted file mode 100644 index a0ea04aad..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByJSONAttributeActionTest.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebServiceConnector; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class SetVariableByJSONAttributeActionTest { - - private SetVariableByJSONAttributeAction setAction; - - @BeforeEach - public void setUp() { - setAction = new SetVariableByJSONAttributeAction(); - setAction.setName("variable"); - setAction.setValue("foo"); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(setAction); - SetVariableByJSONAttributeAction action2 = mapper.readValue(json, SetVariableByJSONAttributeAction.class); - - assertEquals(setAction.getName(), action2.getName()); - assertEquals(setAction.getValue(), action2.getValue()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - URI uri = getClass().getResource("/actions/StoreSymbolActions/SetVariableByJSONAttributeTestData.json").toURI(); - File file = new File(uri); - SymbolAction obj = mapper.readValue(file, SymbolAction.class); - - assertTrue(obj instanceof SetVariableByJSONAttributeAction); - SetVariableByJSONAttributeAction objAsAction = (SetVariableByJSONAttributeAction) obj; - assertEquals("variable", objAsAction.getName()); - assertEquals("foobar", objAsAction.getValue()); - } - - @Test - public void shouldSetTheRightValue() { - VariableStoreConnector storeConnector = mock(VariableStoreConnector.class); - WebServiceConnector webServiceConnector = mock(WebServiceConnector.class); - given(webServiceConnector.getBody()).willReturn("{\"foo\": \"bar\"}"); - ConnectorManager connectors = mock(ConnectorManager.class); - given(connectors.getConnector(VariableStoreConnector.class)).willReturn(storeConnector); - given((connectors.getConnector(WebServiceConnector.class))).willReturn(webServiceConnector); - - ExecuteResult result = setAction.execute(connectors); - - assertTrue(result.isSuccess()); - verify(storeConnector).set("variable", "bar"); - } - - @Test - public void shouldSetNotihingIfThePropertyDoesNotExists() { - VariableStoreConnector storeConnector = mock(VariableStoreConnector.class); - WebServiceConnector webServiceConnector = mock(WebServiceConnector.class); - given(webServiceConnector.getBody()).willReturn("{\"nope\": \"bar\"}"); - ConnectorManager connectors = mock(ConnectorManager.class); - given(connectors.getConnector(VariableStoreConnector.class)).willReturn(storeConnector); - given((connectors.getConnector(WebServiceConnector.class))).willReturn(webServiceConnector); - - ExecuteResult result = setAction.execute(connectors); - - assertFalse(result.isSuccess()); - verify(storeConnector, never()).set(eq("variable"), anyString()); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByNodeAttributeActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByNodeAttributeActionTest.java deleted file mode 100644 index 8ea5ffc1c..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByNodeAttributeActionTest.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; - -public class SetVariableByNodeAttributeActionTest { - - private static final String VARIABLE = "variable"; - private static final String NODE = "node"; - private static final String ATTRIBUTE_NAME = "attribute"; - private static final String ATTRIBUTE_VALUE = "foobar"; - - private SetVariableByNodeAttributeAction setAction; - - private WebElementLocator node; - - @BeforeEach - public void setUp() { - node = new WebElementLocator(); - node.setSelector(NODE); - node.setType(WebElementLocator.Type.CSS); - - Symbol symbol = new Symbol(); - symbol.setProject(new Project(1L)); - - setAction = new SetVariableByNodeAttributeAction(); - setAction.setSymbol(symbol); - setAction.setName(VARIABLE); - setAction.setNode(node); - setAction.setAttribute(ATTRIBUTE_NAME); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(setAction); - SetVariableByNodeAttributeAction declareAction2; - declareAction2 = mapper.readValue(json, SetVariableByNodeAttributeAction.class); - - assertEquals(setAction.getName(), declareAction2.getName()); - assertEquals(setAction.getNode(), declareAction2.getNode()); - assertEquals(setAction.getAttribute(), declareAction2.getAttribute()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - URI uri = getClass().getResource("/actions/StoreSymbolActions/SetVariableByNodeAttributeTestData.json").toURI(); - File file = new File(uri); - SymbolAction obj = mapper.readValue(file, SymbolAction.class); - - assertTrue(obj instanceof SetVariableByNodeAttributeAction); - SetVariableByNodeAttributeAction objAsAction = (SetVariableByNodeAttributeAction) obj; - assertEquals(VARIABLE, objAsAction.getName()); - assertEquals(node, objAsAction.getNode()); - assertEquals(ATTRIBUTE_NAME, objAsAction.getAttribute()); - } - - @Test - public void shouldSetTheVariableIfTheNodeAndAttributeExists() { - ConnectorManager connector = mock(ConnectorManager.class); - VariableStoreConnector variables = mock(VariableStoreConnector.class); - given(connector.getConnector(VariableStoreConnector.class)).willReturn(variables); - - WebElement element = mock(WebElement.class); - given(element.getAttribute(ATTRIBUTE_NAME)).willReturn(ATTRIBUTE_VALUE); - WebSiteConnector webSiteConnector = mock(WebSiteConnector.class); - given(webSiteConnector.getElement(node)).willReturn(element); - given(connector.getConnector(WebSiteConnector.class)).willReturn(webSiteConnector); - - ExecuteResult result = setAction.executeAction(connector); - - assertTrue(result.isSuccess()); - verify(variables).set(VARIABLE, ATTRIBUTE_VALUE); - } - - @Test - public void shouldReturnFailedIfTheNodeDoesNotExists() { - ConnectorManager connector = mock(ConnectorManager.class); - VariableStoreConnector variables = mock(VariableStoreConnector.class); - given(connector.getConnector(VariableStoreConnector.class)).willReturn(variables); - - WebSiteConnector webSiteConnector = mock(WebSiteConnector.class); - given(webSiteConnector.getElement(node)).willThrow(NoSuchElementException.class); - given(connector.getConnector(WebSiteConnector.class)).willReturn(webSiteConnector); - - ExecuteResult result = setAction.executeAction(connector); - - assertFalse(result.isSuccess()); - verify(variables, never()).set(eq(VARIABLE), anyString()); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByNodeCountActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByNodeCountActionTest.java deleted file mode 100644 index 2ed256384..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByNodeCountActionTest.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; - -public class SetVariableByNodeCountActionTest { - - private SetVariableByNodeCountAction action; - - private ConnectorManager connectors; - - private WebSiteConnector webSiteConnector; - - private VariableStoreConnector variableStore; - - private List elements; - - @BeforeEach - public void before() { - this.webSiteConnector = Mockito.mock(WebSiteConnector.class); - this.variableStore = new VariableStoreConnector(); - - this.connectors = Mockito.mock(ConnectorManager.class); - Mockito.when(connectors.getConnector(WebSiteConnector.class)).thenReturn(this.webSiteConnector); - Mockito.when(connectors.getConnector(VariableStoreConnector.class)).thenReturn(this.variableStore); - - final Project project = new Project(1L); - - final Symbol symbol = new Symbol(); - symbol.setId(1L); - symbol.setProject(project); - - this.action = new SetVariableByNodeCountAction(); - this.action.setName("var"); - this.action.setNode(new WebElementLocator(".el", WebElementLocator.Type.CSS)); - this.action.setSymbol(symbol); - - this.elements = Arrays.asList(Mockito.mock(WebElement.class), Mockito.mock(WebElement.class)); - } - - @Test - public void shouldStoreAmountOfNodes() { - Mockito.when(webSiteConnector.getElements(Mockito.any(WebElementLocator.class))).thenReturn(elements); - - final ExecuteResult result = action.executeAction(connectors); - - assertTrue(result.isSuccess()); - assertEquals(String.valueOf(elements.size()), variableStore.get("var")); - } - - @Test - public void shouldStoreZeroIfNoElementsCouldBeFound() { - Mockito.when(webSiteConnector.getElements(Mockito.any(WebElementLocator.class))).thenReturn(new ArrayList<>()); - - final ExecuteResult result = action.executeAction(connectors); - - assertTrue(result.isSuccess()); - assertEquals(String.valueOf(0), variableStore.get("var")); - } - - @Test - public void shouldStoreZeroIfExceptionOccurs() { - Mockito.when(webSiteConnector.getElements(Mockito.any(WebElementLocator.class))).thenThrow(new NoSuchElementException("")); - - final ExecuteResult result = action.executeAction(connectors); - - assertTrue(result.isSuccess()); - assertEquals(String.valueOf(0), variableStore.get("var")); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByRegexGroupActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByRegexGroupActionTest.java deleted file mode 100644 index 38127574e..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/SetVariableByRegexGroupActionTest.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import org.openqa.selenium.WebDriver; - -public class SetVariableByRegexGroupActionTest { - - private static final String VARIABLE_NAME = "var"; - - private SetVariableByRegexGroupAction action; - - private ConnectorManager connectors; - - private WebSiteConnector webSiteConnector; - - private VariableStoreConnector variableStore; - - private WebDriver wd; - - @BeforeEach - public void before() { - this.webSiteConnector = Mockito.mock(WebSiteConnector.class); - this.variableStore = new VariableStoreConnector(); - - this.connectors = Mockito.mock(ConnectorManager.class); - Mockito.when(connectors.getConnector(WebSiteConnector.class)).thenReturn(this.webSiteConnector); - Mockito.when(connectors.getConnector(VariableStoreConnector.class)).thenReturn(this.variableStore); - - this.wd = Mockito.mock(WebDriver.class); - Mockito.when(this.webSiteConnector.getDriver()).thenReturn(this.wd); - - final Project project = new Project(1L); - - final Symbol symbol = new Symbol(); - symbol.setId(1L); - symbol.setProject(project); - - this.action = new SetVariableByRegexGroupAction(); - this.action.setName(VARIABLE_NAME); - this.action.setSymbol(symbol); - this.action.setRegex(".*?([0-9]+).*?"); - - Mockito.when(wd.getPageSource()).thenReturn("a: 1, b: 2"); - } - - @Test - public void shouldSetTheValueCorrectly() { - action.setNthMatch(1); - action.setMthGroup(1); - - final ExecuteResult result1 = action.executeAction(connectors); - assertTrue(result1.isSuccess()); - assertEquals("1", variableStore.get(VARIABLE_NAME)); - - action.setRegex(".*?([0-9]+).*?"); - action.setNthMatch(2); - action.setMthGroup(1); - - final ExecuteResult result2 = action.executeAction(connectors); - assertTrue(result2.isSuccess()); - assertEquals("2", variableStore.get(VARIABLE_NAME)); - } - - @Test - public void shouldFailIfMatchIsOutOfBounds() { - action.setNthMatch(5); - action.setMthGroup(1); - - final ExecuteResult result = action.executeAction(connectors); - assertFalse(result.isSuccess()); - assertNull(variableStore.getStore().get(VARIABLE_NAME)); - } - - @Test - public void shouldFailIfGroupIsOutOfBounds() { - action.setNthMatch(1); - action.setMthGroup(4); - - final ExecuteResult result = action.executeAction(connectors); - assertFalse(result.isSuccess()); - assertNull(variableStore.getStore().get(VARIABLE_NAME)); - } - - @Test - public void shouldFailIfRegexDoesNotMatchBounds() { - Mockito.when(wd.getPageSource()).thenReturn("abc"); - - action.setNthMatch(1); - action.setMthGroup(1); - - final ExecuteResult result = action.executeAction(connectors); - assertFalse(result.isSuccess()); - assertNull(variableStore.getStore().get(VARIABLE_NAME)); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/WaitActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/WaitActionTest.java deleted file mode 100644 index e20c3c2b1..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/misc/WaitActionTest.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.misc; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.mock; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class WaitActionTest { - - private static final Long ONE_SECOND = 1000L; - - private WaitAction w; - - @BeforeEach - public void setUp() { - w = new WaitAction(); - w.setDuration(ONE_SECOND); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(w); - WaitAction w2 = mapper.readValue(json, WaitAction.class); - - assertEquals(w.getDuration(), w2.getDuration()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - File file = new File(getClass().getResource("/actions/WaitTestData.json").toURI()); - SymbolAction obj = mapper.readValue(file, SymbolAction.class); - - assertTrue(obj instanceof SymbolAction); - WaitAction objAsAction = (WaitAction) obj; - assertEquals(ONE_SECOND, objAsAction.getDuration()); - } - - @Test - public void shouldReturnOKIfTimeIsUp() { - ConnectorManager connector = mock(ConnectorManager.class); - assertTrue(w.execute(connector).isSuccess()); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CallActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CallActionTest.java deleted file mode 100644 index 50ed1bd70..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CallActionTest.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.rest; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anySet; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.verify; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolAction; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.HashMap; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class CallActionTest extends RestActionTest { - - private static final String BASE_URL = "Base"; - private static final String TEST_BASE_URL = "http://example.com/api"; - private static final String TEST_API_PATH = "/test"; - - @Mock - private Symbol symbol; - - private CallAction c; - - @BeforeEach - public void setUp() { - super.setUp(); - - c = new CallAction(); - c.setSymbol(symbol); - c.setMethod(CallAction.Method.GET); - c.setUrl(TEST_API_PATH); - c.setBaseUrl(BASE_URL); - HashMap cookies = new HashMap<>(); - cookies.put("cookie", "Lorem Ipsum"); - c.setCookies(cookies); - c.setData("{}"); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(c); - CallAction c2 = mapper.readValue(json, CallAction.class); - - assertEquals(c.getMethod(), c2.getMethod()); - assertEquals(c.getUrl(), c2.getUrl()); - assertEquals(c.getData(), c2.getData()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - File file = new File(getClass().getResource("/actions/restsymbolactions/CallActionTestData.json").toURI()); - SymbolAction obj = mapper.readValue(file, SymbolAction.class); - - assertTrue(obj instanceof CallAction); - CallAction objAsAction = (CallAction) obj; - assertEquals(CallAction.Method.GET, objAsAction.getMethod()); - assertEquals(TEST_BASE_URL, objAsAction.getUrl()); - assertEquals(1, objAsAction.getHeaders().size()); // assert header - assertEquals("Foobar, Bar", objAsAction.getHeaders().get("X-MyHeader")); - assertEquals(c.getCookies().size(), objAsAction.getCookies().size()); // assert cookies - assertEquals(c.getCookies().get("cookie"), objAsAction.getCookies().get("cookie")); - assertEquals("{}", objAsAction.getData()); - } - - @Test - public void shouldDoAValidGetCall() throws Exception { - ExecuteResult result = c.executeAction(connectors); - - assertTrue(result.isSuccess()); - verify(webServiceConnector).get(eq(BASE_URL), eq(TEST_API_PATH), any(), anySet(), eq(0)); - } - - @Test - public void shouldDoAValidPostCall() throws Exception { - c.setMethod(CallAction.Method.POST); - - ExecuteResult result = c.executeAction(connectors); - - assertTrue(result.isSuccess()); - verify(webServiceConnector).post(eq(BASE_URL), eq(TEST_API_PATH), any(), anySet(), eq("{}"), eq(0)); - } - - @Test - public void shouldDoAValidPutCall() throws Exception { - c.setMethod(CallAction.Method.PUT); - - ExecuteResult result = c.executeAction(connectors); - - assertTrue(result.isSuccess()); - verify(webServiceConnector).put(eq(BASE_URL), eq(TEST_API_PATH), any(), anySet(), eq("{}"), eq(0)); - } - - @Test - public void shouldDoAValidDeleteCall() throws Exception { - c.setMethod(CallAction.Method.DELETE); - - ExecuteResult result = c.executeAction(connectors); - - assertTrue(result.isSuccess()); - verify(webServiceConnector).delete(eq(BASE_URL), eq(TEST_API_PATH), any(), anySet(), eq(0)); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CheckAttributeExistsActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CheckAttributeExistsActionTest.java deleted file mode 100644 index 66fa13968..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CheckAttributeExistsActionTest.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.rest; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Symbol; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class CheckAttributeExistsActionTest extends RestActionTest { - - @Mock - private Symbol symbol; - - private CheckAttributeExistsAction c; - - @BeforeEach - public void setUp() { - super.setUp(); - - c = new CheckAttributeExistsAction(); - c.setSymbol(symbol); - c.setAttribute("awesome_field"); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(c); - CheckAttributeExistsAction c2 = mapper.readValue(json, CheckAttributeExistsAction.class); - - assertEquals(c.getAttribute(), c2.getAttribute()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - String path = "/actions/restsymbolactions/CheckAttributeExistsTestData.json"; - File file = new File(getClass().getResource(path).toURI()); - RESTSymbolAction obj = mapper.readValue(file, RESTSymbolAction.class); - - assertTrue(obj instanceof CheckAttributeExistsAction); - CheckAttributeExistsAction objAsAction = (CheckAttributeExistsAction) obj; - assertEquals("object.attribute", objAsAction.getAttribute()); - } - - @Test - public void shouldReturnOkIfAttributeExists() { - given(webServiceConnector.getBody()).willReturn("{\"awesome_field\": \"Lorem Ipsum. Hello World! Fooooobar\"}"); - - ExecuteResult result = c.executeAction(connectors); - - assertTrue(result.isSuccess()); - } - - @Test - public void shouldReturnOkIfAttributeExistsWithComplexStructure() { - given(webServiceConnector.getBody()).willReturn("{\"awesome_field\": {\"foo\": \"Fooooobar.\"," - + "\"other\": [\"Lorem Ipsum.\", \"Hello World!\"]}}"); - c.setAttribute("awesome_field.foo"); - - ExecuteResult result = c.executeAction(connectors); - - assertTrue(result.isSuccess()); - } - - @Test - public void shouldReturnFailedIfAttributeDoesNotExists() { - given(webServiceConnector.getBody()).willReturn("{\"not_so_awesome_field\": \"Lorem Ipsum. Hello World! Fooooobar\"}"); - - ExecuteResult result = c.executeAction(connectors); - - assertFalse(result.isSuccess()); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CheckAttributeTypeActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CheckAttributeTypeActionTest.java deleted file mode 100644 index 5c8ed402a..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CheckAttributeTypeActionTest.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.rest; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Symbol; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class CheckAttributeTypeActionTest extends RestActionTest { - - @Mock - private Symbol symbol; - - private CheckAttributeTypeAction c; - - @BeforeEach - public void setUp() { - super.setUp(); - - c = new CheckAttributeTypeAction(); - c.setSymbol(symbol); - c.setAttribute("awesome_field"); - c.setJsonType(CheckAttributeTypeAction.JsonType.STRING); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(c); - CheckAttributeTypeAction c2 = mapper.readValue(json, CheckAttributeTypeAction.class); - - assertEquals(c.getAttribute(), c2.getAttribute()); - assertEquals(c.getJsonType(), c2.getJsonType()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - String path = "/actions/restsymbolactions/CheckAttributeTypeTestData.json"; - File file = new File(getClass().getResource(path).toURI()); - RESTSymbolAction obj = mapper.readValue(file, RESTSymbolAction.class); - - assertTrue(obj instanceof CheckAttributeTypeAction); - CheckAttributeTypeAction objAsAction = (CheckAttributeTypeAction) obj; - assertEquals("object.attribute", objAsAction.getAttribute()); - assertEquals(CheckAttributeTypeAction.JsonType.STRING, objAsAction.getJsonType()); - } - - @Test - public void shouldReturnOkIfAttributeWithRightTypeExists() { - given(webServiceConnector.getBody()).willReturn("{\"awesome_field\": \"Lorem Ipsum. Hello World! Fooooobar\"}"); - - ExecuteResult result = c.executeAction(connectors); - assertTrue(result.isSuccess()); - } - - @Test - public void shouldReturnOkIfAttributeWithRightTypeExistsWithComplexStructure() { - given(webServiceConnector.getBody()).willReturn("{\"awesome_field\": {\"foo\": \"Fooooobar.\"," - + "\"other\": [\"Lorem Ipsum.\", \"Hello World!\"]}}"); - c.setAttribute("awesome_field.foo"); - - ExecuteResult result = c.executeAction(connectors); - assertTrue(result.isSuccess()); - } - - @Test - public void shouldReturnFailedIfAttributeWithWrongTypeExists() { - given(webServiceConnector.getBody()).willReturn("{\"awesome_field\": true}"); - - ExecuteResult result = c.executeAction(connectors); - assertFalse(result.isSuccess()); - } - - @Test - public void shouldReturnFailedIfAttributeDoesNotExist() { - given(webServiceConnector.getBody()).willReturn("{\"not_so_awesome_field\": \"Lorem Ipsum. Hello World! Fooooobar\"}"); - - ExecuteResult result = c.executeAction(connectors); - assertFalse(result.isSuccess()); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CheckAttributeValueActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CheckAttributeValueActionTest.java deleted file mode 100644 index 5c1cc6043..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CheckAttributeValueActionTest.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.rest; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Symbol; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class CheckAttributeValueActionTest extends RestActionTest { - - @Mock - private Symbol symbol; - - private CheckAttributeValueAction c; - - @BeforeEach - public void setUp() { - super.setUp(); - - c = new CheckAttributeValueAction(); - c.setSymbol(symbol); - c.setAttribute("awesome_field"); - c.setValue("Hello World!"); - c.setRegexp(false); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(c); - CheckAttributeValueAction c2 = mapper.readValue(json, CheckAttributeValueAction.class); - - assertEquals(c.getAttribute(), c2.getAttribute()); - assertEquals(c.getValue(), c2.getValue()); - assertEquals(c.isRegexp(), c2.isRegexp()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - String path = "/actions/restsymbolactions/CheckAttributeValueTestData.json"; - File file = new File(getClass().getResource(path).toURI()); - RESTSymbolAction obj = mapper.readValue(file, RESTSymbolAction.class); - - assertTrue(obj instanceof CheckAttributeValueAction); - CheckAttributeValueAction objAsAction = (CheckAttributeValueAction) obj; - assertEquals("object.attribute", objAsAction.getAttribute()); - assertEquals("FooBar Lorem", objAsAction.getValue()); - assertEquals(true, objAsAction.isRegexp()); - } - - @Test - public void shouldReturnOkIfPathExistsOnJsonArray() { - CheckAttributeValueAction action = new CheckAttributeValueAction(); - action.setSymbol(symbol); - action.setAttribute("[0].id"); - action.setValue("0"); - action.setRegexp(false); - - given(webServiceConnector.getBody()).willReturn("[{\"id\": 0}]"); - - ExecuteResult result = action.executeAction(connectors); - assertTrue(result.isSuccess()); - } - - @Test - public void shouldReturnNullIfThePathIsInvalidOnJsonArray() { - CheckAttributeValueAction action = new CheckAttributeValueAction(); - action.setSymbol(symbol); - action.setAttribute("[0].id"); - action.setValue("0"); - action.setRegexp(false); - - given(webServiceConnector.getBody()).willReturn("[{\"id\": 6}]"); - - ExecuteResult result = action.executeAction(connectors); - assertFalse(result.isSuccess()); - } - - @Test - public void shouldReturnOkIfAttributeWithRightValueExists() { - given(webServiceConnector.getBody()).willReturn("{\"awesome_field\": \"Hello World!\"}"); - - ExecuteResult result = c.executeAction(connectors); - assertTrue(result.isSuccess()); - } - - @Test - public void shouldReturnOkIfAttributeWithRightValueExistsWithComplexStructure() { - given(webServiceConnector.getBody()).willReturn("{\"awesome_field\": {\"foo\": \"Hello World!\"," - + "\"other\": [\"Lorem Ipsum.\", \"Fooooobar.\"]}}"); - c.setAttribute("awesome_field.foo"); - - ExecuteResult result = c.executeAction(connectors); - assertTrue(result.isSuccess()); - } - - @Test - public void shouldReturnFailedIfAttributeWithWrongValueExists() { - given(webServiceConnector.getBody()).willReturn("{\"awesome_field\": \"Lorem Ipsum!\"}"); - - ExecuteResult result = c.executeAction(connectors); - assertFalse(result.isSuccess()); - } - - @Test - public void shouldReturnFailedIfAttributeDoesNotExist() { - given(webServiceConnector.getBody()).willReturn("{\"not_so_awesome_field\": \"Lorem Ipsum. Hello World! Fooooobar\"}"); - - ExecuteResult result = c.executeAction(connectors); - assertFalse(result.isSuccess()); - } - - @Test - public void shouldReturnFailedIfJSONIsEmpty() { - given(webServiceConnector.getBody()).willReturn(""); - - ExecuteResult result = c.executeAction(connectors); - assertFalse(result.isSuccess()); - } - - @Test - public void shouldReturnOKIfTextWasFoundWithRegexp() { - c.setValue("F[oO]+ B[a]+r"); - c.setRegexp(true); - given(webServiceConnector.getBody()).willReturn("{\"awesome_field\": \"FoO Baaaaar\"}"); - - assertTrue(c.executeAction(connectors).isSuccess()); - } - - @Test - public void shouldReturnFailedIfTextWasNotFoundWithRegexp() { - c.setValue("F[oO]+ B[a]+r"); - c.setRegexp(true); - given(webServiceConnector.getBody()).willReturn("{\"awesome_field\": \"F Bar\"}"); - - assertFalse(c.executeAction(connectors).isSuccess()); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CheckForTextActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CheckForTextActionTest.java deleted file mode 100644 index a12c83b37..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CheckForTextActionTest.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.rest; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Symbol; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class CheckForTextActionTest extends RestActionTest { - - @Mock - private Symbol symbol; - - private CheckTextRestAction c; - - @BeforeEach - public void setUp() { - super.setUp(); - - c = new CheckTextRestAction(); - c.setSymbol(symbol); - c.setValue("Hello World"); - c.setRegexp(false); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(c); - CheckTextRestAction c2 = mapper.readValue(json, CheckTextRestAction.class); - - assertEquals(c.getValue(), c2.getValue()); - assertEquals(c.isRegexp(), c2.isRegexp()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - File file = new File(getClass().getResource("/actions/restsymbolactions/CheckForTextTestData.json").toURI()); - RESTSymbolAction obj = mapper.readValue(file, RESTSymbolAction.class); - - assertTrue(obj instanceof CheckTextRestAction); - CheckTextRestAction objAsAction = (CheckTextRestAction) obj; - assertEquals("Lorem Ipsum", objAsAction.getValue()); - assertEquals(true, objAsAction.isRegexp()); - } - - @Test - public void shouldReturnOkIfBodyContainsTheText() { - given(webServiceConnector.getBody()).willReturn("{\"awesome_field\": \"Lorem Ipsum. Hello World! Fooooobar\"}"); - - ExecuteResult result = c.executeAction(connectors); - - assertTrue(result.isSuccess()); - } - - @Test - public void shouldReturnFailedIfBodyContainsNotTheText() { - given(webServiceConnector.getBody()).willReturn("{\"awesome_field\": \"Lorem Ipsum. Fooooobar\"}"); - - ExecuteResult result = c.executeAction(connectors); - assertFalse(result.isSuccess()); - } - - @Test - public void shouldReturnOKIfTextWasFoundWithRegexp() { - c.setValue("F[oO]+ B[a]+r"); - c.setRegexp(true); - given(webServiceConnector.getBody()).willReturn("FoO Baaaaar"); - - assertTrue(c.executeAction(connectors).isSuccess()); - } - - @Test - public void shouldReturnFailedIfTextWasNotFoundWithRegexp() { - c.setValue("F[oO]+ B[a]+r"); - c.setRegexp(true); - given(webServiceConnector.getBody()).willReturn("F BAr"); - - assertFalse(c.executeAction(connectors).isSuccess()); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CheckHeaderFieldActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CheckHeaderFieldActionTest.java deleted file mode 100644 index 392a30271..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CheckHeaderFieldActionTest.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.rest; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Symbol; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.Arrays; -import javax.ws.rs.core.MultivaluedHashMap; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class CheckHeaderFieldActionTest extends RestActionTest { - - @Mock - private Symbol symbol; - - private CheckHeaderFieldAction c; - - @BeforeEach - public void setUp() { - super.setUp(); - - c = new CheckHeaderFieldAction(); - c.setSymbol(symbol); - c.setKey("Accept"); - c.setValue("text/html"); - c.setRegexp(false); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(c); - CheckHeaderFieldAction c2 = mapper.readValue(json, CheckHeaderFieldAction.class); - - assertEquals(c.getKey(), c2.getKey()); - assertEquals(c.getValue(), c2.getValue()); - assertEquals(c.isRegexp(), c2.isRegexp()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - String path = "/actions/restsymbolactions/CheckHeaderFieldTestData.json"; - File file = new File(getClass().getResource(path).toURI()); - RESTSymbolAction obj = mapper.readValue(file, RESTSymbolAction.class); - - assertTrue(obj instanceof CheckHeaderFieldAction); - CheckHeaderFieldAction objAsAction = (CheckHeaderFieldAction) obj; - assertEquals("Key", objAsAction.getKey()); - assertEquals("Value", objAsAction.getValue()); - assertEquals(true, objAsAction.isRegexp()); - } - - @Test - public void shouldReturnOkIfHeaderFieldWithTheValueExists() { - MultivaluedHashMap headers = createHeaders("text/html", "application/xhtml+xml"); - given(webServiceConnector.getHeaders()).willReturn(headers); - - ExecuteResult result = c.executeAction(connectors); - - assertTrue(result.isSuccess()); - } - - @Test - public void shouldReturnFailedIfHeaderFieldWithoutValue() { - MultivaluedHashMap headers = createHeaders("application/xhtml+xml"); - given(webServiceConnector.getHeaders()).willReturn(headers); - - ExecuteResult result = c.executeAction(connectors); - - assertFalse(result.isSuccess()); - } - - @Test - public void shouldReturnFailedIfHeaderFieldDoesNotExists() { - MultivaluedHashMap headers = mock(MultivaluedHashMap.class); - given(webServiceConnector.getHeaders()).willReturn(headers); - - ExecuteResult result = c.executeAction(connectors); - assertFalse(result.isSuccess()); - } - - @Test - public void shouldReturnOKIfTextWasFoundWithRegexp() { - c.setValue("F[oO]+ B[a]+r"); - c.setRegexp(true); - MultivaluedHashMap headers = createHeaders("text/html", "FoO Baaaaar", "application/xhtml+xml"); - given(webServiceConnector.getHeaders()).willReturn(headers); - - assertTrue(c.executeAction(connectors).isSuccess()); - } - - @Test - public void shouldReturnFailedIfTextWasNotFoundWithRegexp() { - c.setValue("F[oO]+ B[a]+r"); - c.setRegexp(true); - MultivaluedHashMap headers = createHeaders("text/html", "F BAr", "application/xhtml+xml"); - given(webServiceConnector.getHeaders()).willReturn(headers); - - assertFalse(c.executeAction(connectors).isSuccess()); - } - - private MultivaluedHashMap createHeaders(String... data) { - MultivaluedHashMap headers = mock(MultivaluedHashMap.class); - given(headers.get("Accept")).willReturn(Arrays.asList(data)); - return headers; - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CheckStatusActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CheckStatusActionTest.java deleted file mode 100644 index 5591822e9..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/CheckStatusActionTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.rest; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.learning.services.connectors.WebServiceConnector; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import javax.ws.rs.core.Response; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class CheckStatusActionTest { - - @Mock - private WebServiceConnector connector; - - private CheckStatusAction c; - - @BeforeEach - public void setUp() { - c = new CheckStatusAction(); - c.setStatus(Response.Status.OK.getStatusCode()); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(c); - CheckStatusAction c2 = mapper.readValue(json, CheckStatusAction.class); - - assertEquals(c.getStatus(), c2.getStatus()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - File file = new File(getClass().getResource("/actions/restsymbolactions/CheckStatusTestData.json").toURI()); - RESTSymbolAction obj = mapper.readValue(file, RESTSymbolAction.class); - - assertTrue(obj instanceof CheckStatusAction); - CheckStatusAction objAsAction = (CheckStatusAction) obj; - assertEquals(Response.Status.OK.getStatusCode(), objAsAction.getStatus()); - } - - @Test - public void shouldAcceptCorrectStatus() { - given(connector.getStatus()).willReturn(Response.Status.OK.getStatusCode()); - - ExecuteResult result = c.execute(connector); - assertTrue(result.isSuccess()); - } - - @Test - public void shouldFailOnWrongStatus() { - given(connector.getStatus()).willReturn(Response.Status.BAD_REQUEST.getStatusCode()); - - ExecuteResult result = c.execute(connector); - assertFalse(result.isSuccess()); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/RESTSymbolTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/RESTSymbolTest.java deleted file mode 100644 index 15baf0ce3..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/RESTSymbolTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.rest; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolActionStep; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.CounterStoreConnector; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class RESTSymbolTest { - - private Symbol symbol; - private RESTSymbolAction action1; - private RESTSymbolAction action2; - - private ConnectorManager connectors; - - @BeforeEach - public void setUp() { - action1 = mock(RESTSymbolAction.class); - action2 = mock(RESTSymbolAction.class); - - final SymbolActionStep step1 = new SymbolActionStep(); - step1.setAction(action1); - - final SymbolActionStep step2 = new SymbolActionStep(); - step2.setAction(action2); - - symbol = new Symbol(); - symbol.getSteps().add(step1); - symbol.getSteps().add(step2); - - connectors = mock(ConnectorManager.class); - given(connectors.getConnector(VariableStoreConnector.class)).willReturn(mock(VariableStoreConnector.class)); - given(connectors.getConnector(CounterStoreConnector.class)).willReturn(mock(CounterStoreConnector.class)); - } - - @Test - public void shouldReturnOkIfAllActionsRunSuccessfully() throws Exception { - given(action1.executeAction(connectors)).willReturn(new ExecuteResult(true)); - given(action2.executeAction(connectors)).willReturn(new ExecuteResult(true)); - - ExecuteResult result = symbol.execute(connectors); - assertTrue(result.isSuccess()); - } - - @Test - public void shouldReturnFailedIfOneActionsRunFailed() throws Exception { - given(action1.executeAction(connectors)).willReturn(new ExecuteResult(false)); - given(action2.executeAction(connectors)).willReturn(new ExecuteResult(true)); - - ExecuteResult result = symbol.execute(connectors); - - assertFalse(result.isSuccess()); - verify(action2, never()).executeAction(connectors); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/RestActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/RestActionTest.java deleted file mode 100644 index 49da101ab..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/rest/RestActionTest.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.rest; - -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.mock; - -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.WebServiceConnector; - -public class RestActionTest { - - protected ConnectorManager connectors; - - protected WebServiceConnector webServiceConnector; - - protected void setUp() { - connectors = mock(ConnectorManager.class); - webServiceConnector = mock(WebServiceConnector.class); - lenient().when(connectors.getConnector(WebServiceConnector.class)).thenReturn(webServiceConnector); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/AlertAcceptDismissActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/AlertAcceptDismissActionTest.java deleted file mode 100644 index 2e6adbeab..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/AlertAcceptDismissActionTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import org.openqa.selenium.Alert; -import org.openqa.selenium.NoAlertPresentException; -import org.openqa.selenium.WebDriver; - -public class AlertAcceptDismissActionTest { - - private AlertAcceptDismissAction action; - - private ConnectorManager connectors; - - private WebDriver.TargetLocator targetLocator; - - @BeforeEach - public void before() { - final WebSiteConnector webSiteConnector = Mockito.mock(WebSiteConnector.class); - - this.connectors = Mockito.mock(ConnectorManager.class); - Mockito.when(connectors.getConnector(WebSiteConnector.class)).thenReturn(webSiteConnector); - - final WebDriver wd = Mockito.mock(WebDriver.class); - Mockito.when(webSiteConnector.getDriver()).thenReturn(wd); - - this.targetLocator = Mockito.mock(WebDriver.TargetLocator.class); - Mockito.when(wd.switchTo()).thenReturn(this.targetLocator); - - this.action = new AlertAcceptDismissAction(); - } - - @Test - public void shouldFailIfNoAlertIsPresent() { - Mockito.when(targetLocator.alert()).thenThrow(new NoAlertPresentException()); - - final ExecuteResult result = action.execute(connectors); - assertFalse(result.isSuccess()); - } - - @Test - public void shouldSucceedIfAlertIsPresent() { - final Alert alert = Mockito.mock(Alert.class); - Mockito.when(targetLocator.alert()).thenReturn(alert); - - action.setAction(AlertAcceptDismissAction.Action.ACCEPT); - final ExecuteResult res1 = action.execute(connectors); - assertTrue(res1.isSuccess()); - Mockito.verify(alert, Mockito.times(1)).accept(); - - action.setAction(AlertAcceptDismissAction.Action.DISMISS); - final ExecuteResult res2 = action.execute(connectors); - assertTrue(res2.isSuccess()); - Mockito.verify(alert, Mockito.times(1)).dismiss(); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/AlertGetTextActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/AlertGetTextActionTest.java deleted file mode 100644 index 0133de026..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/AlertGetTextActionTest.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import org.openqa.selenium.Alert; -import org.openqa.selenium.NoAlertPresentException; -import org.openqa.selenium.WebDriver; - -public class AlertGetTextActionTest { - - private static final String VARIABLE_NAME = "var"; - - private AlertGetTextAction action; - - private ConnectorManager connectors; - - private WebSiteConnector webSiteConnector; - - private VariableStoreConnector variableStore; - - private WebDriver.TargetLocator targetLocator; - - @BeforeEach - public void before() { - this.webSiteConnector = Mockito.mock(WebSiteConnector.class); - this.variableStore = new VariableStoreConnector(); - - this.connectors = Mockito.mock(ConnectorManager.class); - Mockito.when(connectors.getConnector(WebSiteConnector.class)).thenReturn(this.webSiteConnector); - Mockito.when(connectors.getConnector(VariableStoreConnector.class)).thenReturn(this.variableStore); - - final Project project = new Project(1L); - final Symbol symbol = new Symbol(); - symbol.setId(1L); - symbol.setProject(project); - - this.action = new AlertGetTextAction(); - this.action.setVariableName(VARIABLE_NAME); - this.action.setSymbol(symbol); - - this.targetLocator = Mockito.mock(WebDriver.TargetLocator.class); - - final WebDriver wd = Mockito.mock(WebDriver.class); - Mockito.when(wd.switchTo()).thenReturn(this.targetLocator); - Mockito.when(this.webSiteConnector.getDriver()).thenReturn(wd); - } - - @Test - public void shouldStoreTextInVariableAndSucceed() { - final Alert alert = Mockito.mock(Alert.class); - Mockito.when(targetLocator.alert()).thenReturn(alert); - Mockito.when(alert.getText()).thenReturn("test"); - - final ExecuteResult result = action.executeAction(connectors); - assertTrue(result.isSuccess()); - assertEquals("test", variableStore.get(VARIABLE_NAME)); - } - - @Test - public void shouldFailWhenNoAlertIsPresent() { - Mockito.when(targetLocator.alert()).thenThrow(new NoAlertPresentException()); - - final ExecuteResult result = action.executeAction(connectors); - assertFalse(result.isSuccess()); - assertThrows(IllegalStateException.class, () -> variableStore.get(VARIABLE_NAME)); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/CheckNodeActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/CheckNodeActionTest.java deleted file mode 100644 index 35f53f737..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/CheckNodeActionTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.WebElementLocator; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; - -@ExtendWith(MockitoExtension.class) -public class CheckNodeActionTest extends WebActionTest { - - private CheckNodeAction checkNode; - - private WebElementLocator node; - - @BeforeEach - public void setUp() { - super.setUp(); - - Symbol symbol = new Symbol(); - - node = new WebElementLocator(); - node.setSelector("#node"); - node.setType(WebElementLocator.Type.CSS); - - checkNode = new CheckNodeAction(); - checkNode.setSymbol(symbol); - checkNode.setNode(node); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(checkNode); - CheckNodeAction c2 = mapper.readValue(json, CheckNodeAction.class); - - assertEquals(checkNode.getNode(), c2.getNode()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - File file = new File(getClass().getResource("/actions/websymbolactions/CheckNodeTestData.json").toURI()); - WebSymbolAction obj = mapper.readValue(file, WebSymbolAction.class); - - assertTrue(obj instanceof CheckNodeAction); - CheckNodeAction objAsAction = (CheckNodeAction) obj; - assertEquals("#node", objAsAction.getNode().getSelector()); - assertEquals(WebElementLocator.Type.CSS, objAsAction.getNode().getType()); - } - - @Test - public void shouldReturnOKIfNodeWasFound() { - WebElement element = mock(WebElement.class); - given(webSiteConnector.getElement(node)).willReturn(element); - - assertTrue(checkNode.executeAction(connectors).isSuccess()); - } - - @Test - public void shouldReturnFailedIfNodeWasNotFound() { - when(webSiteConnector.getElement(node)).thenThrow(new NoSuchElementException("")); - - assertFalse(checkNode.executeAction(connectors).isSuccess()); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/CheckNodeSelectedActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/CheckNodeSelectedActionTest.java deleted file mode 100644 index 29fb5f014..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/CheckNodeSelectedActionTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.WebElementLocator; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; - -@ExtendWith(MockitoExtension.class) -public class CheckNodeSelectedActionTest extends WebActionTest { - - private CheckNodeSelectedAction action; - - private WebElementLocator node; - - @BeforeEach - public void setUp() { - super.setUp(); - - Symbol symbol = new Symbol(); - - node = new WebElementLocator(); - node.setSelector("#node"); - node.setType(WebElementLocator.Type.CSS); - - action = new CheckNodeSelectedAction(); - action.setSymbol(symbol); - action.setNode(node); - } - - @Test - public void shouldReturnOkIfNodeWasFoundAndSelected() { - WebElement element = mock(WebElement.class); - given(element.isSelected()).willReturn(true); - given(webSiteConnector.getElement(node)).willReturn(element); - - assertTrue(action.executeAction(connectors).isSuccess()); - } - - @Test - public void shouldReturnFailedIfNodeWasFoundAndNotSelected() { - WebElement element = mock(WebElement.class); - given(element.isSelected()).willReturn(false); - given(webSiteConnector.getElement(node)).willReturn(element); - - assertFalse(action.executeAction(connectors).isSuccess()); - } - - @Test - public void shouldReturnFailedIfNodeWasNotFound() { - given(webSiteConnector.getElement(node)).willThrow(new NoSuchElementException("")); - - assertFalse(action.executeAction(connectors).isSuccess()); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/CheckPageTitleActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/CheckPageTitleActionTest.java deleted file mode 100644 index 1e3163da1..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/CheckPageTitleActionTest.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.mock; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.learning.services.connectors.CounterStoreConnector; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; -import org.openqa.selenium.WebDriver; - -@ExtendWith(MockitoExtension.class) -public class CheckPageTitleActionTest extends WebActionTest { - - private static final long PROJECT_ID = 1; - - private static final String TEST_TITLE = "Awesome Title No. {{#title}}"; - - private CheckPageTitleAction checkNode; - private ObjectMapper objectMapper = new ObjectMapper(); - - @BeforeEach - public void setUp() { - super.setUp(); - - Project project = new Project(); - project.setId(PROJECT_ID); - - Symbol symbol = new Symbol(); - symbol.setProject(project); - - checkNode = new CheckPageTitleAction(); - checkNode.setSymbol(symbol); - checkNode.setTitle(TEST_TITLE); - checkNode.setRegexp(false); - } - - @Test - public void testJSON() throws IOException { - String json = objectMapper.writeValueAsString(checkNode); - CheckPageTitleAction c2 = objectMapper.readValue(json, CheckPageTitleAction.class); - - assertEquals(checkNode.getTitle(), c2.getTitle()); - assertEquals(checkNode.isRegexp(), c2.isRegexp()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - File file = new File(getClass().getResource("/actions/websymbolactions/CheckPageTitleTestData.json").toURI()); - WebSymbolAction obj = objectMapper.readValue(file, WebSymbolAction.class); - - assertTrue(obj instanceof CheckPageTitleAction); - CheckPageTitleAction objAsAction = (CheckPageTitleAction) obj; - assertEquals(TEST_TITLE, objAsAction.getTitle()); - assertTrue(objAsAction.isRegexp()); - } - - @Test - public void shouldReturnOKIfTitleWasFoundWithoutRegex() { - WebDriver driver = mock(WebDriver.class); - given((webSiteConnector.getDriver())).willReturn(driver); - given(driver.getTitle()).willReturn("Awesome Title No. 0"); - - CounterStoreConnector counterStoreConnector = mock(CounterStoreConnector.class); - lenient().when(connectors.getConnector(CounterStoreConnector.class)).thenReturn(counterStoreConnector); - - assertTrue(checkNode.executeAction(connectors).isSuccess()); - } - - @Test - public void shouldReturnFailedIfTitleWasNotFoundWithoutRegex() { - WebDriver driver = mock(WebDriver.class); - given((webSiteConnector.getDriver())).willReturn(driver); - given(driver.getTitle()).willReturn("This is the wrong title"); - - CounterStoreConnector counterStoreConnector = mock(CounterStoreConnector.class); - lenient().when(connectors.getConnector(CounterStoreConnector.class)).thenReturn(counterStoreConnector); - - assertFalse(checkNode.executeAction(connectors).isSuccess()); - } - - @Test - public void shouldReturnOKIfTitleWasFoundWithRegex() { - WebDriver driver = mock(WebDriver.class); - given((webSiteConnector.getDriver())).willReturn(driver); - given(driver.getTitle()).willReturn("Fo0obar"); - - checkNode.setTitle("F[o0]*bar"); - checkNode.setRegexp(true); - - assertTrue(checkNode.executeAction(connectors).isSuccess()); - } - - @Test - public void shouldReturnFailedIfTitleWasNotFoundWithRegex() { - WebDriver driver = mock(WebDriver.class); - given((webSiteConnector.getDriver())).willReturn(driver); - given(driver.getTitle()).willReturn("This is the wrong title"); - - checkNode.setTitle("f[o0]+bar"); - checkNode.setRegexp(true); - - assertFalse(checkNode.executeAction(connectors).isSuccess()); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/CheckTextWebActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/CheckTextWebActionTest.java deleted file mode 100644 index 8e208904d..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/CheckTextWebActionTest.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.mock; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolAction; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.CounterStoreConnector; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; - -@ExtendWith(MockitoExtension.class) -public class CheckTextWebActionTest extends WebActionTest { - - private CheckTextWebAction checkText; - - private ObjectMapper mapper; - - @BeforeEach - public void setUp() { - super.setUp(); - mapper = new ObjectMapper(); - - Symbol symbol = new Symbol(); - symbol.setProject(new Project(1L)); - - checkText = new CheckTextWebAction(); - checkText.setSymbol(symbol); - checkText.setValue("Foobar"); - checkText.setRegexp(false); - checkText.setNode(new WebElementLocator("document", WebElementLocator.Type.CSS)); - - lenient().when(connectors.getConnector(VariableStoreConnector.class)).thenReturn(mock(VariableStoreConnector.class)); - lenient().when(connectors.getConnector(CounterStoreConnector.class)).thenReturn(mock(CounterStoreConnector.class)); - lenient().when(webSiteConnector.getDriver()).thenReturn(mock(WebDriver.class)); - } - - @Test - public void testJSON() throws IOException { - String json = mapper.writeValueAsString(checkText); - CheckTextWebAction c2 = (CheckTextWebAction) mapper.readValue(json, SymbolAction.class); - - assertEquals(checkText.getValue(), c2.getValue()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - File file = new File(getClass().getResource("/actions/websymbolactions/CheckTextTestData.json").toURI()); - SymbolAction obj = mapper.readValue(file, SymbolAction.class); - - assertTrue(obj instanceof CheckTextWebAction); - CheckTextWebAction c = (CheckTextWebAction) obj; - assertEquals("Lorem Ipsum", c.getValue()); - } - - @Test - public void shouldEncodeHtmlCharsInValue() { - given(webSiteConnector.getDriver().getPageSource()).willReturn(createHtmlDoc("
this is a $& test
")); - checkText.setValue("this is a $& test"); - - assertTrue(checkText.executeAction(connectors).isSuccess()); - } - - @Test - public void shouldReturnOKIfTextWasFoundWithoutRegexp() { - given(webSiteConnector.getDriver().getPageSource()).willReturn(checkText.getValue()); - - assertTrue(checkText.executeAction(connectors).isSuccess()); - } - - @Test - public void shouldReturnFailedIfTextWasNotFoundWithoutRegexp() { - given(webSiteConnector.getDriver().getPageSource()).willReturn(""); - - assertFalse(checkText.executeAction(connectors).isSuccess()); - } - - @Test - public void shouldReturnOKIfTextWasFoundWithRegexp() { - checkText.setValue("F[oO]+ B[a]+r"); - checkText.setRegexp(true); - - given(webSiteConnector.getDriver().getPageSource()).willReturn("FoO Baaaaar"); - - assertTrue(checkText.executeAction(connectors).isSuccess()); - } - - @Test - public void shouldReturnFailedIfTextWasNotFoundWithRegexp() { - checkText.setValue("F[oO]+ B[a]+r"); - checkText.setRegexp(true); - - given(webSiteConnector.getDriver().getPageSource()).willReturn("F BAr"); - - assertFalse(checkText.executeAction(connectors).isSuccess()); - } - - @Test - public void shouldOnlyLookForTextInTheCorrectElement() { - WebElement fooElement = mock(WebElement.class); - given(fooElement.getAttribute("innerHTML")).willReturn("foo"); - - WebElement barElement = mock(WebElement.class); - given(barElement.getAttribute("innerHTML")).willReturn("bar"); - - checkText.setValue("foo"); - checkText.getNode().setSelector("#foo"); - - given(webSiteConnector.getElement(checkText.getNode())).willReturn(fooElement); - - assertTrue(checkText.executeAction(connectors).isSuccess()); - - checkText.getNode().setSelector("#bar"); - - given(webSiteConnector.getElement(checkText.getNode())).willReturn(barElement); - - assertFalse(checkText.executeAction(connectors).isSuccess()); - } - - private String createHtmlDoc(String content) { - return "" + content + ""; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/ClickActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/ClickActionTest.java deleted file mode 100644 index efedc703e..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/ClickActionTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.WebElementLocator; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; - -@ExtendWith(MockitoExtension.class) -public class ClickActionTest extends WebActionTest { - - private ClickAction c; - - private WebElementLocator node; - - @BeforeEach - public void setUp() { - super.setUp(); - - Symbol symbol = new Symbol(); - symbol.setProject(new Project(1L)); - - node = new WebElementLocator(); - node.setSelector("#node"); - node.setType(WebElementLocator.Type.CSS); - - c = new ClickAction(); - c.setSymbol(symbol); - c.setNode(node); - c.setDoubleClick(false); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(c); - ClickAction c2 = mapper.readValue(json, ClickAction.class); - - assertEquals(c.getNode(), c2.getNode()); - assertEquals(c.isDoubleClick(), c2.isDoubleClick()); - } - - @Test - public void testJSONWithLongNode() throws IOException { - c.getNode().setSelector("#superlong > css trace .with-absolute ~no_meaning .at-all > .1234567890 > .1234567890 " - + "> .1234567890" - + " > .1234567890 > .1234567890 > .1234567890 > .1234567890 > .1234567890 > .1234567890" - + " > .1234567890 > .1234567890 > .1234567890"); - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(c); - ClickAction c2 = mapper.readValue(json, ClickAction.class); - - assertEquals(c.getNode(), c2.getNode()); - assertEquals(c.isDoubleClick(), c2.isDoubleClick()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - File file = new File(getClass().getResource("/actions/websymbolactions/ClickTestData.json").toURI()); - WebSymbolAction obj = mapper.readValue(file, WebSymbolAction.class); - - assertTrue(obj instanceof ClickAction); - ClickAction objAsAction = (ClickAction) obj; - assertEquals(node, objAsAction.getNode()); - } - - @Test - public void shouldReturnOKIfNodeCouldBeClicked() { - WebElement element = mock(WebElement.class); - given(webSiteConnector.getElement(node)).willReturn(element); - - assertTrue(c.executeAction(connectors).isSuccess()); - verify(element).click(); - } - - @Test - public void shouldReturnFailedIfNodeCouldNotBeClicked() { - given(webSiteConnector.getElement(node)).willThrow(new NoSuchElementException("")); - - assertFalse(c.executeAction(connectors).isSuccess()); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/ClickElementByTextActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/ClickElementByTextActionTest.java deleted file mode 100644 index 269381149..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/ClickElementByTextActionTest.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.CounterStoreConnector; -import de.learnlib.alex.learning.services.connectors.VariableStoreConnector; -import java.util.ArrayList; -import java.util.List; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; -import org.openqa.selenium.By; -import org.openqa.selenium.WebElement; - -@ExtendWith(MockitoExtension.class) -public class ClickElementByTextActionTest extends WebActionTest { - - private static final String TAG_NAME = "button"; - - private static final String TEXT = "test"; - - private final WebElement container = mock(WebElement.class); - - private ClickElementByTextAction action; - - @BeforeEach - public void setUp() { - super.setUp(); - - final Symbol symbol = new Symbol(); - symbol.setProject(new Project(0L)); - - action = new ClickElementByTextAction(); - action.setNode(new WebElementLocator("body", WebElementLocator.Type.CSS)); - action.setTagName(TAG_NAME); - action.setText(TEXT); - action.setSymbol(symbol); - - lenient().when(connectors.getConnector(VariableStoreConnector.class)).thenReturn(mock(VariableStoreConnector.class)); - lenient().when(connectors.getConnector(CounterStoreConnector.class)).thenReturn(mock(CounterStoreConnector.class)); - lenient().when(webSiteConnector.getElement(action.getNode())).thenReturn(container); - } - - @Test - public void shouldFailIfNoElementWithTagNameIsFound() { - given(container.findElements(By.tagName(TAG_NAME))).willReturn(new ArrayList<>()); - - final ExecuteResult result = action.executeAction(connectors); - assertFalse(result.isSuccess()); - } - - @Test - public void shouldFailIfElementIsNotEnabled() { - final WebElement button = mock(WebElement.class); - given(button.getText()).willReturn(TEXT); - - final List elements = new ArrayList<>(); - elements.add(button); - - given(container.findElements(By.tagName(TAG_NAME))).willReturn(elements); - - final ExecuteResult result = action.executeAction(connectors); - assertFalse(result.isSuccess()); - } - - @Test - public void shouldFailIfElementIsNotVisible() { - final WebElement button = mock(WebElement.class); - given(button.getText()).willReturn(TEXT); - - final List elements = new ArrayList<>(); - elements.add(button); - - given(button.isDisplayed()).willReturn(false); - given(container.findElements(By.tagName(TAG_NAME))).willReturn(elements); - - final ExecuteResult result = action.executeAction(connectors); - assertFalse(result.isSuccess()); - } - - @Test - public void shouldClickOnTheFirstClickableElement() { - final WebElement button1 = mock(WebElement.class); - given(button1.getText()).willReturn(TEXT); - - final WebElement button2 = mock(WebElement.class); - given(button1.getText()).willReturn(TEXT); - - final List elements = new ArrayList<>(); - elements.add(button1); - elements.add(button2); - - given(button1.isDisplayed()).willReturn(false); - given(button2.getText()).willReturn(TEXT); - given(button2.isDisplayed()).willReturn(true); - given(button2.isEnabled()).willReturn(true); - given(container.findElements(By.tagName(TAG_NAME))).willReturn(elements); - - final ExecuteResult result = action.executeAction(connectors); - assertTrue(result.isSuccess()); - - verify(button1, never()).click(); - verify(button2).click(); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/ClickLinkActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/ClickLinkActionTest.java deleted file mode 100644 index f60225176..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/ClickLinkActionTest.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.WebElementLocator; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; -import org.openqa.selenium.By; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; - -@ExtendWith(MockitoExtension.class) -public class ClickLinkActionTest extends WebActionTest { - - private ClickLinkAction action; - - @BeforeEach - public void setUp() { - super.setUp(); - - Symbol symbol = new Symbol(); - - action = new ClickLinkAction(); - action.setSymbol(symbol); - action.setValue("Click Me"); - action.setNode(new WebElementLocator("body", WebElementLocator.Type.CSS)); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(action); - ClickLinkAction c2 = mapper.readValue(json, ClickLinkAction.class); - - assertEquals(action.getValue(), c2.getValue()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - File file = new File(getClass().getResource("/actions/websymbolactions/ClickLinkTestData.json").toURI()); - WebSymbolAction obj = mapper.readValue(file, WebSymbolAction.class); - - assertTrue(obj instanceof ClickLinkAction); - ClickLinkAction objAsAction = (ClickLinkAction) obj; - assertEquals("Click Me", objAsAction.getValue()); - } - - @Test - public void shouldReturnOKIfLinkCouldBeClicked() { - WebElement body = mock(WebElement.class); - WebElement fooLink = mock(WebElement.class); - - given(webSiteConnector.getElement(action.getNode())).willReturn(body); - given(body.findElement(By.linkText(action.getValue()))).willReturn(fooLink); - - assertTrue(action.executeAction(connectors).isSuccess()); - verify(fooLink).click(); - } - - @Test - public void shouldReturnFailedIfLinkCouldNotBeClicked() { - WebElement body = mock(WebElement.class); - - given(webSiteConnector.getElement(action.getNode())).willReturn(body); - - when(body.findElement(By.linkText("Click Me"))).thenThrow(new NoSuchElementException("")); - - assertFalse(action.executeAction(connectors).isSuccess()); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/ExecuteScriptActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/ExecuteScriptActionTest.java deleted file mode 100644 index 085527706..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/ExecuteScriptActionTest.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.SymbolAction; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class ExecuteScriptActionTest { - - private ExecuteScriptAction action; - - @BeforeEach - public void setUp() { - action = new ExecuteScriptAction(); - action.setScript("document.write('hello')"); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(action); - ExecuteScriptAction c2 = mapper.readValue(json, ExecuteScriptAction.class); - - assertEquals(action.getScript(), c2.getScript()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - File file = new File(getClass().getResource("/actions/websymbolactions/ExecuteScriptTestData.json").toURI()); - SymbolAction obj = mapper.readValue(file, SymbolAction.class); - - assertTrue(obj instanceof ExecuteScriptAction); - ExecuteScriptAction objAsAction = (ExecuteScriptAction) obj; - assertEquals("document.write('hello')", objAsAction.getScript()); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/FillActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/FillActionTest.java deleted file mode 100644 index fd424cf39..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/FillActionTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.WebElementLocator; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; - -@ExtendWith(MockitoExtension.class) -public class FillActionTest extends WebActionTest { - - private FillAction f; - - private WebElementLocator node; - - @BeforeEach - public void setUp() { - super.setUp(); - - Symbol symbol = new Symbol(); - - node = new WebElementLocator(); - node.setSelector("#node"); - node.setType(WebElementLocator.Type.CSS); - - f = new FillAction(); - f.setSymbol(symbol); - f.setNode(node); - f.setValue("Lorem Ipsum"); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(f); - FillAction f2 = mapper.readValue(json, FillAction.class); - - assertEquals(f.getNode(), f2.getNode()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - File file = new File(getClass().getResource("/actions/websymbolactions/FillTestData.json").toURI()); - WebSymbolAction obj = mapper.readValue(file, WebSymbolAction.class); - - assertTrue(obj instanceof FillAction); - FillAction objAsAction = (FillAction) obj; - assertEquals("#input", objAsAction.getNode().getSelector()); - assertEquals("Lorem Ipsum", objAsAction.getValue()); - } - - @Test - public void shouldReturnOKIfNodeCouldBeFilled() { - WebElement element = mock(WebElement.class); - given(webSiteConnector.getElement(node)).willReturn(element); - - assertTrue(f.executeAction(connectors).isSuccess()); - verify(element).sendKeys(f.getValue()); - } - - @Test - public void shouldReturnFailedIfNodeCouldNotBeFilled() { - when(webSiteConnector.getElement(node)).thenThrow(new NoSuchElementException("")); - - assertFalse(f.executeAction(connectors).isSuccess()); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/GotoActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/GotoActionTest.java deleted file mode 100644 index 763aeccc1..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/GotoActionTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.BDDMockito.willThrow; -import static org.mockito.Mockito.verify; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.actions.Credentials; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class GotoActionTest extends WebActionTest { - - private static final String BASE_URL = "Base"; - private static final String FAKE_URL = "http://example.com/"; - - private GotoAction g; - - @BeforeEach - public void setUp() { - super.setUp(); - - Symbol symbol = new Symbol(); - - g = new GotoAction(); - g.setSymbol(symbol); - g.setUrl(FAKE_URL); - g.setBaseUrl(BASE_URL); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(g); - GotoAction c2 = mapper.readValue(json, GotoAction.class); - - assertEquals(g.getUrl(), c2.getUrl()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - File file = new File(getClass().getResource("/actions/websymbolactions/GotoTestData.json").toURI()); - WebSymbolAction obj = mapper.readValue(file, WebSymbolAction.class); - - assertTrue(obj instanceof GotoAction); - GotoAction objAsAction = (GotoAction) obj; - assertEquals("http://example.com/", objAsAction.getUrl()); - } - - @Test - public void shouldReturnOKIfTheUrlCouldBeFound() throws Exception { - assertTrue(g.executeAction(connectors).isSuccess()); - verify(webSiteConnector).get(eq(BASE_URL), eq(FAKE_URL), any(Credentials.class)); - } - - @Test - public void shouldReturnFailedIfTheUrlCouldNotBeFound() throws Exception { - willThrow(Exception.class).given(webSiteConnector).get(eq(BASE_URL), eq(FAKE_URL), any(Credentials.class)); - assertFalse(g.executeAction(connectors).isSuccess()); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/MoveMouseActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/MoveMouseActionTest.java deleted file mode 100644 index 4e8ae7bfe..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/MoveMouseActionTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.WebElementLocator; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebDriver; - -@ExtendWith(MockitoExtension.class) -public class MoveMouseActionTest extends WebActionTest { - - private MoveMouseAction c; - - private WebElementLocator node; - - @BeforeEach - public void setUp() { - super.setUp(); - - Symbol symbol = new Symbol(); - - node = new WebElementLocator(); - node.setSelector("#node"); - node.setType(WebElementLocator.Type.CSS); - - c = new MoveMouseAction(); - c.setSymbol(symbol); - c.setNode(node); - c.setOffsetX(0); - c.setOffsetY(0); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(c); - MoveMouseAction c2 = mapper.readValue(json, MoveMouseAction.class); - - assertEquals(c.getNode(), c2.getNode()); - assertEquals(c.getOffsetX(), c2.getOffsetX()); - assertEquals(c.getOffsetY(), c2.getOffsetY()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - File file = new File(getClass().getResource("/actions/websymbolactions/MoveMouseTestData.json").toURI()); - WebSymbolAction obj = mapper.readValue(file, WebSymbolAction.class); - - assertTrue(obj instanceof MoveMouseAction); - MoveMouseAction objAsAction = (MoveMouseAction) obj; - assertEquals(node, objAsAction.getNode()); - assertEquals(0, objAsAction.getOffsetX()); - assertEquals(0, objAsAction.getOffsetY()); - } - - @Test - public void shouldReturnFAILEDIfNodeCouldNotBeClicked() { - when(webSiteConnector.getDriver()).thenReturn(mock(WebDriver.class)); - when(webSiteConnector.getElement(node)).thenThrow(new NoSuchElementException("")); - - assertFalse(c.executeAction(connectors).isSuccess()); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/SubmitActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/SubmitActionTest.java deleted file mode 100644 index 96afdee7c..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/SubmitActionTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.WebElementLocator; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebElement; - -@ExtendWith(MockitoExtension.class) -public class SubmitActionTest extends WebActionTest { - - private SubmitAction s; - - private WebElementLocator node; - - @BeforeEach - public void setUp() { - super.setUp(); - - Symbol symbol = new Symbol(); - - node = new WebElementLocator(); - node.setSelector("#node"); - node.setType(WebElementLocator.Type.CSS); - - s = new SubmitAction(); - s.setSymbol(symbol); - s.setNode(node); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(s); - SubmitAction s2 = mapper.readValue(json, SubmitAction.class); - - assertEquals(s.getNode(), s2.getNode()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - File file = new File(getClass().getResource("/actions/websymbolactions/SubmitTestData.json").toURI()); - WebSymbolAction obj = mapper.readValue(file, WebSymbolAction.class); - - assertTrue(obj instanceof SubmitAction); - SubmitAction objAsAction = (SubmitAction) obj; - assertEquals(node, objAsAction.getNode()); - } - - @Test - public void shouldReturnOKIfNodeCouldBeSubmitted() { - WebElement element = mock(WebElement.class); - given(webSiteConnector.getElement(node)).willReturn(element); - - assertTrue(s.executeAction(connectors).isSuccess()); - verify(element).submit(); - } - - @Test - public void shouldReturnFailedIfNodeCouldNotBeSubmitted() { - when(webSiteConnector.getElement(node)).thenThrow(new NoSuchElementException("")); - - assertFalse(s.executeAction(connectors).isSuccess()); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/WaitForNodeActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/WaitForNodeActionTest.java deleted file mode 100644 index d455cdf42..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/WaitForNodeActionTest.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; -import org.openqa.selenium.StaleElementReferenceException; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; - -@ExtendWith(MockitoExtension.class) -public class WaitForNodeActionTest extends WebActionTest { - - private static final int MAX_WAIT_TIME = 5; - - private WaitForNodeAction action; - - private WebElementLocator node; - - @BeforeEach - public void setUp() { - super.setUp(); - - Symbol symbol = new Symbol(); - symbol.setProject(new Project(1L)); - - node = new WebElementLocator(); - node.setSelector("#node"); - node.setType(WebElementLocator.Type.CSS); - - action = new WaitForNodeAction(); - action.setSymbol(symbol); - action.setNode(node); - action.setWaitCriterion(WaitForNodeAction.WaitCriterion.VISIBLE); - action.setMaxWaitTime(MAX_WAIT_TIME); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(action); - WaitForNodeAction action2 = mapper.readValue(json, WaitForNodeAction.class); - - assertEquals(action.getNode(), action2.getNode()); - assertEquals(action.getWaitCriterion(), action2.getWaitCriterion()); - assertEquals(action.getMaxWaitTime(), action2.getMaxWaitTime()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - File file = new File(getClass().getResource("/actions/websymbolactions/WaitForNodeTestData.json").toURI()); - WebSymbolAction obj = mapper.readValue(file, WebSymbolAction.class); - - assertTrue(obj instanceof WaitForNodeAction); - WaitForNodeAction objAsAction = (WaitForNodeAction) obj; - assertEquals(node, objAsAction.getNode()); - assertEquals(WaitForNodeAction.WaitCriterion.ADDED, objAsAction.getWaitCriterion()); - assertEquals(MAX_WAIT_TIME, objAsAction.getMaxWaitTime()); - } - - @Test - public void shouldWaitUntilTheElementIsVisible() { - WebDriver driver = mock(WebDriver.class); - given(webSiteConnector.getDriver()).willReturn(driver); - WebElement element = mock(WebElement.class); - given(webSiteConnector.getElement(node)).willReturn(element); - given(element.isDisplayed()).willReturn(true); - action.setWaitCriterion(WaitForNodeAction.WaitCriterion.VISIBLE); - action.setMaxWaitTime(MAX_WAIT_TIME); - - ExecuteResult result = action.executeAction(connectors); - assertTrue(result.isSuccess()); - } - - @Test - public void shouldWaitUntilTheElementIsInvisible() { - WebDriver driver = mock(WebDriver.class); - given(webSiteConnector.getDriver()).willReturn(driver); - WebElement element = mock(WebElement.class); - - given(element.isDisplayed()).willReturn(false); - given(connectors.getConnector(WebSiteConnector.class).getElement(node)).willReturn(element); - - action.setWaitCriterion(WaitForNodeAction.WaitCriterion.INVISIBLE); - action.setMaxWaitTime(MAX_WAIT_TIME); - - ExecuteResult result = action.executeAction(connectors); - assertTrue(result.isSuccess()); - } - - @Test - public void shouldWaitUntilTheElementIsAdded() { - WebDriver driver = mock(WebDriver.class); - given(webSiteConnector.getDriver()).willReturn(driver); - WebElement element = mock(WebElement.class); - given(webSiteConnector.getElement(node)).willReturn(element); - - action.setWaitCriterion(WaitForNodeAction.WaitCriterion.ADDED); - action.setMaxWaitTime(MAX_WAIT_TIME); - - ExecuteResult result = action.executeAction(connectors); - assertTrue(result.isSuccess()); - } - - @Test - public void shouldWaitUntilTheElementIsRemoved() { - WebDriver driver = mock(WebDriver.class); - given(webSiteConnector.getDriver()).willReturn(driver); - given(webSiteConnector.getElement(node)).willThrow(StaleElementReferenceException.class); - action.setWaitCriterion(WaitForNodeAction.WaitCriterion.REMOVED); - action.setMaxWaitTime(MAX_WAIT_TIME); - - ExecuteResult result = action.executeAction(connectors); - assertTrue(result.isSuccess()); - } - - @Test - public void shouldFailOnTimeout() { - WebDriver driver = mock(WebDriver.class); - given(webSiteConnector.getDriver()).willReturn(driver); - WebElement element = mock(WebElement.class); - given(webSiteConnector.getElement(node)).willReturn(element); - action.setWaitCriterion(WaitForNodeAction.WaitCriterion.VISIBLE); - action.setMaxWaitTime(0); // don't really wait to keep the test speed high - - ExecuteResult result = action.executeAction(connectors); - assertFalse(result.isSuccess()); - } - - @Test - public void shouldFailIfMaxTimeToWaitIsNegative() { - action.setMaxWaitTime(-1); - - ExecuteResult result = action.executeAction(connectors); - assertFalse(result.isSuccess()); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/WaitForNodeAttributeActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/WaitForNodeAttributeActionTest.java deleted file mode 100644 index f5a1e9da3..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/WaitForNodeAttributeActionTest.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.WebElementLocator; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; - -public class WaitForNodeAttributeActionTest { - - private WaitForNodeAttributeAction action; - - private ConnectorManager connectors; - - private WebSiteConnector webSiteConnector; - - private WebElement el; - - @BeforeEach - public void before() { - this.webSiteConnector = Mockito.mock(WebSiteConnector.class); - - this.connectors = Mockito.mock(ConnectorManager.class); - Mockito.when(this.connectors.getConnector(WebSiteConnector.class)).thenReturn(this.webSiteConnector); - - final Project project = new Project(1L); - final Symbol symbol = new Symbol(); - symbol.setId(1L); - symbol.setProject(project); - - this.action = new WaitForNodeAttributeAction(); - this.action.setSymbol(symbol); - this.action.setNode(new WebElementLocator()); - this.action.setAttribute("id"); - this.action.setMaxWaitTime(0); - - this.el = Mockito.mock(WebElement.class); - Mockito.when(this.webSiteConnector.getElement(Mockito.any(WebElementLocator.class))).thenReturn(this.el); - Mockito.when(this.webSiteConnector.getDriver()).thenReturn(Mockito.mock(WebDriver.class)); - } - - @Test - public void shouldWaitUntilAttributeIsValue() { - Mockito.when(el.getAttribute("id")).thenReturn("test"); - action.setWaitCriterion(WaitForNodeAttributeAction.WaitCriterion.IS); - action.setValue("test"); - final ExecuteResult result = action.executeAction(connectors); - assertTrue(result.isSuccess()); - } - - @Test - public void shouldWaitUntilAttributeContainsValue() { - Mockito.when(el.getAttribute("id")).thenReturn("1test2"); - action.setWaitCriterion(WaitForNodeAttributeAction.WaitCriterion.CONTAINS); - action.setValue("test"); - final ExecuteResult result = action.executeAction(connectors); - assertTrue(result.isSuccess()); - } - - @Test - public void shouldFailOnNegativeWaitTime() { - action.setMaxWaitTime(-1L); - final ExecuteResult result = action.executeAction(connectors); - assertFalse(result.isSuccess()); - } - - @Test - public void shouldFailOnTimeout() { - Mockito.when(el.getAttribute("id")).thenReturn("someId"); - action.setWaitCriterion(WaitForNodeAttributeAction.WaitCriterion.IS); - action.setValue("test"); - final ExecuteResult result1 = action.executeAction(connectors); - assertFalse(result1.isSuccess()); - - action.setWaitCriterion(WaitForNodeAttributeAction.WaitCriterion.CONTAINS); - action.setValue("test"); - final ExecuteResult result2 = action.executeAction(connectors); - assertFalse(result2.isSuccess()); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/WaitForTitleActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/WaitForTitleActionTest.java deleted file mode 100644 index 4149e910b..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/WaitForTitleActionTest.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; -import org.openqa.selenium.WebDriver; - -@ExtendWith(MockitoExtension.class) -public class WaitForTitleActionTest extends WebActionTest { - - private static final int ONE_MINUTE = 60; - - private WaitForTitleAction action; - - @BeforeEach - public void setUp() { - super.setUp(); - - Symbol symbol = new Symbol(); - symbol.setProject(new Project(1L)); - - action = new WaitForTitleAction(); - action.setSymbol(symbol); - action.setValue("Title"); - action.setWaitCriterion(WaitForTitleAction.WaitCriterion.CONTAINS); - action.setMaxWaitTime(ONE_MINUTE); - } - - @Test - public void testJSON() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - String json = mapper.writeValueAsString(action); - WaitForTitleAction action2 = mapper.readValue(json, WaitForTitleAction.class); - - assertEquals(action.getValue(), action2.getValue()); - assertEquals(action.getWaitCriterion(), action2.getWaitCriterion()); - assertEquals(action.getMaxWaitTime(), action2.getMaxWaitTime()); - } - - @Test - public void testJSONFile() throws IOException, URISyntaxException { - ObjectMapper mapper = new ObjectMapper(); - - File file = new File(getClass().getResource("/actions/websymbolactions/WaitForTitleTestData.json").toURI()); - WebSymbolAction obj = mapper.readValue(file, WebSymbolAction.class); - - assertTrue(obj instanceof WaitForTitleAction); - WaitForTitleAction objAsAction = (WaitForTitleAction) obj; - assertEquals("#node", objAsAction.getValue()); - assertEquals(WaitForTitleAction.WaitCriterion.CONTAINS, objAsAction.getWaitCriterion()); - assertEquals(ONE_MINUTE, objAsAction.getMaxWaitTime()); - } - - @Test - public void shouldWaitUntilTheTitleIsTheExpectedValue() { - WebDriver driver = mock(WebDriver.class); - given(webSiteConnector.getDriver()).willReturn(driver); - given(driver.getTitle()).willReturn(action.getValue()); - action.setWaitCriterion(WaitForTitleAction.WaitCriterion.IS); - action.setMaxWaitTime(ONE_MINUTE); - - ExecuteResult result = action.executeAction(connectors); - assertTrue(result.isSuccess()); - } - - @Test - public void shouldWaitUntilTheTitleContainsTheExpectedValue() { - WebDriver driver = mock(WebDriver.class); - given(webSiteConnector.getDriver()).willReturn(driver); - given(driver.getTitle()).willReturn(action.getValue() + " - extra stuff that should not matter!"); - action.setWaitCriterion(WaitForTitleAction.WaitCriterion.CONTAINS); - action.setMaxWaitTime(ONE_MINUTE); - - ExecuteResult result = action.executeAction(connectors); - assertTrue(result.isSuccess()); - } - - @Test - public void shouldFailOnTimeout() { - WebDriver driver = mock(WebDriver.class); - given(driver.getTitle()).willReturn("test title"); - given(webSiteConnector.getDriver()).willReturn(driver); - action.setWaitCriterion(WaitForTitleAction.WaitCriterion.IS); - action.setMaxWaitTime(0); // don't really wait to keep the test speed high - - ExecuteResult result = action.executeAction(connectors); - assertFalse(result.isSuccess()); - } - - @Test - public void shouldFailIfMaxTimeToWaitIsNegative() { - action.setMaxWaitTime(-1); - - ExecuteResult result = action.executeAction(connectors); - assertFalse(result.isSuccess()); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/WebActionTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/WebActionTest.java deleted file mode 100644 index 2ff67dd63..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/WebActionTest.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.mock; - -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import de.learnlib.alex.learning.services.connectors.WebSiteConnector; - -public abstract class WebActionTest { - - protected ConnectorManager connectors; - - protected WebSiteConnector webSiteConnector; - - protected void setUp() { - connectors = mock(ConnectorManager.class); - webSiteConnector = mock(WebSiteConnector.class); - lenient().when(connectors.getConnector(WebSiteConnector.class)).thenReturn(webSiteConnector); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/WebSymbolTest.java b/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/WebSymbolTest.java deleted file mode 100644 index d9382d499..000000000 --- a/backend/src/test/java/de/learnlib/alex/data/entities/actions/web/WebSymbolTest.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.data.entities.actions.web; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolActionStep; -import de.learnlib.alex.data.entities.SymbolGroup; -import de.learnlib.alex.data.entities.actions.misc.WaitAction; -import de.learnlib.alex.learning.services.connectors.ConnectorManager; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.Arrays; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class WebSymbolTest { - - private static final Long ONE_SECOND = 1000L; - - private Symbol symbol; - - private ObjectMapper mapper; - - @BeforeEach - public void setUp() { - mapper = new ObjectMapper(); - - User user = new User(); - user.setId(42L); - - Project project = new Project(); - project.setId(1L); - project.setName("Web Symbol Test Project"); - - SymbolGroup group = new SymbolGroup(); - group.setId(2L); - group.setName("Web Symbol Test Project"); - - symbol = new Symbol(); - symbol.setProject(project); - symbol.setGroup(group); - symbol.setName("WebSymbol"); - - WebSymbolAction a1 = new ClickAction(); - a1.setId(1L); - CheckTextWebAction a2 = new CheckTextWebAction(); - a2.setId(2L); - a2.setValue("F[oO0]+"); - a2.setRegexp(true); - WaitAction a3 = new WaitAction(); - a3.setId(3L); - a3.setDuration(ONE_SECOND); - - final SymbolActionStep step1 = new SymbolActionStep(); - step1.setPosition(0); - step1.setAction(a1); - - final SymbolActionStep step2 = new SymbolActionStep(); - step2.setPosition(1); - step2.setAction(a2); - - final SymbolActionStep step3 = new SymbolActionStep(); - step3.setPosition(2); - step3.setAction(a3); - - symbol.getSteps().addAll(Arrays.asList(step1, step2, step3)); - } - - @Test - public void ensureThatSerializingAndThenDeserializingChangesNothing() throws IOException { - String json = mapper.writeValueAsString(symbol); - - Symbol symbolFromMapper = mapper.readValue(json, Symbol.class); - assertEquals(symbol.getProjectId(), symbolFromMapper.getProjectId()); - assertEquals(symbol.getId(), symbolFromMapper.getId()); - assertEquals(symbol.getName(), symbolFromMapper.getName()); - assertEquals(symbol.getGroupId(), symbolFromMapper.getGroupId()); - } - - @Test - public void shouldReadJSONFileCorrectly() throws IOException, URISyntaxException { - File file = new File(getClass().getResource("/actions/websymbolactions/WebSymbolTestData.json").toURI()); - symbol = mapper.readValue(file, Symbol.class); - - assertEquals("Test Symbol", symbol.getName()); - - Class[] expectedActions = { - CheckNodeAction.class, - CheckTextWebAction.class, - ClearAction.class, - ClickAction.class, - FillAction.class, - SubmitAction.class, - WaitAction.class - }; - - assertEquals(expectedActions.length, symbol.getSteps().size()); - for (int i = 0; i < expectedActions.length; i++) { - assertTrue(expectedActions[i].isInstance(((SymbolActionStep) symbol.getSteps().get(i)).getAction())); - } - } - - @Test - public void shouldReturnOkIfAllActionsRunSuccessfully() throws Exception { - ConnectorManager connector = mock(ConnectorManager.class); - WebSymbolAction action1 = mock(WebSymbolAction.class); - given(action1.executeAction(connector)).willReturn(new ExecuteResult(true)); - WebSymbolAction action2 = mock(WebSymbolAction.class); - given(action2.executeAction(connector)).willReturn(new ExecuteResult(true)); - - final SymbolActionStep s1 = new SymbolActionStep(action1); - final SymbolActionStep s2 = new SymbolActionStep(action2); - - symbol = new Symbol(); - symbol.getSteps().addAll(Arrays.asList(s1, s2)); - - assertTrue(symbol.execute(connector).isSuccess()); - } - - @Test - public void shouldReturnFailedIfOneActionFails() throws Exception { - ConnectorManager connector = mock(ConnectorManager.class); - WebSymbolAction action1 = mock(WebSymbolAction.class); - given(action1.executeAction(connector)).willReturn(new ExecuteResult(false)); - WebSymbolAction action2 = mock(WebSymbolAction.class); - - final SymbolActionStep s1 = new SymbolActionStep(action1); - final SymbolActionStep s2 = new SymbolActionStep(action2); - - symbol = new Symbol(); - symbol.getSteps().addAll(Arrays.asList(s1, s2)); - - assertFalse(symbol.execute(connector).isSuccess()); - verify(action2, never()).execute(connector); - } - - private String createActionSteps(Long symbolId) { - return "[" - + "{\"id\": null, \"errorOutput\":null, \"negated\":false, \"ignoreFailure\": false, \"position\": 0, \"symbol\": " + symbolId + ", \"disabled\": false, \"type\": \"action\", \"action\": {\"id\": 1,\"type\":\"web_click\",\"node\":null,\"doubleClick\":false}}" - + ",{\"id\": null, \"errorOutput\":null, \"negated\":false, \"ignoreFailure\": false, \"position\": 1, \"symbol\": " + symbolId + ", \"disabled\": false, \"type\": \"action\", \"action\": {\"id\": 2,\"type\":\"web_checkForText\",\"value\":\"F[oO0]+\",\"regexp\":true,\"node\":{\"selector\":\"document\",\"type\":\"CSS\"}}}" - + ",{\"id\": null, \"errorOutput\":null, \"negated\":false, \"ignoreFailure\": false, \"position\": 2, \"symbol\": " + symbolId + ", \"disabled\": false, \"type\": \"action\", \"action\": {\"id\": 3,\"type\":\"wait\",\"duration\":1000}}" - + "]"; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/SpringRestError.java b/backend/src/test/java/de/learnlib/alex/integrationtests/SpringRestError.java deleted file mode 100644 index be56179fe..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/SpringRestError.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests; - -public class SpringRestError { - - private int statusCode; - - private String statusText; - - private String message; - - public int getStatusCode() { - return statusCode; - } - - public void setStatusCode(int statusCode) { - this.statusCode = statusCode; - } - - public String getStatusText() { - return statusText; - } - - public void setStatusText(String statusText) { - this.statusText = statusText; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/TestPostgresqlContainer.java b/backend/src/test/java/de/learnlib/alex/integrationtests/TestPostgresqlContainer.java deleted file mode 100644 index 0bcb2f055..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/TestPostgresqlContainer.java +++ /dev/null @@ -1,31 +0,0 @@ -package de.learnlib.alex.integrationtests; - -import org.testcontainers.containers.PostgreSQLContainer; - -public class TestPostgresqlContainer extends PostgreSQLContainer { - private static final String IMAGE_VERSION = "postgres:13.2"; - private static TestPostgresqlContainer container; - - private TestPostgresqlContainer() { - super(IMAGE_VERSION); - } - - public static TestPostgresqlContainer getInstance() { - if (container == null) { - container = new TestPostgresqlContainer(); - } - return container; - } - - @Override - public void start() { - super.start(); - System.setProperty("DB_URL", container.getJdbcUrl()); - System.setProperty("DB_USERNAME", container.getUsername()); - System.setProperty("DB_PASSWORD", container.getPassword()); - } - - @Override - public void stop() { - } -} \ No newline at end of file diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/AbstractRepositoryIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/AbstractRepositoryIT.java deleted file mode 100644 index ae7126545..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/AbstractRepositoryIT.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.repositories; - -import de.learnlib.alex.auth.dao.UserDAO; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.auth.repositories.UserRepository; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.data.entities.ProjectUrl; -import de.learnlib.alex.data.entities.SymbolGroup; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.integrationtests.TestPostgresqlContainer; -import de.learnlib.alex.settings.dao.SettingsDAO; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.transaction.annotation.Transactional; -import org.testcontainers.containers.PostgreSQLContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; - -@Testcontainers -@ExtendWith(SpringExtension.class) -@SpringBootTest( - webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT -) -public abstract class AbstractRepositoryIT { - - @Container - public static PostgreSQLContainer postgreSQLContainer = TestPostgresqlContainer.getInstance(); - - @Autowired - protected UserDAO userDAO; - - @Autowired - protected ProjectDAO projectDAO; - - @Autowired - protected UserRepository userRepository; - - @Autowired - protected ProjectRepository projectRepository; - - @Autowired - private SettingsDAO settingsDAO; - - @AfterEach - @Transactional - public void tearDown() { - final var admin = userDAO.getByID(1L); - - // delete all users except the admin - for (var user : userRepository.findAll()) { - if (!user.equals(admin)) { - userDAO.delete(admin, user.getId()); - } - } - - // delete projects of admin - for (var project : projectDAO.getAll(admin)) { - projectDAO.delete(admin, project.getId()); - } - - final var settings = settingsDAO.get(); - settings.setAllowUserRegistration(true); - settingsDAO.update(settings); - } - - User createUser(String email) { - User user = new User(); - user.setUsername(email.split("@")[0]); - user.setEmail(email); - user.setPassword("test"); - return user; - } - - Project createProject(User user, String name) { - final ProjectEnvironment env = new ProjectEnvironment(); - env.setName("Testing"); - env.setDefault(true); - - final ProjectUrl url = new ProjectUrl(); - url.setUrl("http://localhost/"); - url.setEnvironment(env); - env.getUrls().add(url); - - final Project project = new Project(); - project.addOwner(user); - project.setName(name); - project.getEnvironments().add(env); - env.setProject(project); - - SymbolGroup defaultGroup = new SymbolGroup(); - defaultGroup.setProject(project); - defaultGroup.setId(0L); - defaultGroup.setName("Default group"); - - project.getGroups().add(defaultGroup); - return project; - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/CounterRepositoryIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/CounterRepositoryIT.java deleted file mode 100644 index 835c20d06..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/CounterRepositoryIT.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.repositories; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.entities.Counter; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.repositories.CounterRepository; -import java.util.List; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.dao.EmptyResultDataAccessException; - -public class CounterRepositoryIT extends AbstractRepositoryIT { - - @Autowired - private CounterRepository counterRepository; - - private User user; - - private Project project; - - @BeforeEach - public void before() { - User user = createUser("alex@test.example"); - this.user = userRepository.save(user); - - Project project = createProject(user, "Test Project 1"); - this.project = projectRepository.save(project); - } - - @Test - public void shouldCreateAValidCounter() { - Counter counter = createCounter(project, "TestCounter"); - counter = counterRepository.save(counter); - - assertNotNull(counter.getId()); - assertEquals(1, counterRepository.count()); - } - - @Test - public void shouldFailToSaveACounterWithoutAProject() { - Counter counter = createCounter(null, "TestCounter"); - - assertThrows(DataIntegrityViolationException.class, () -> counterRepository.save(counter)); - } - - @Test - public void shouldFailToSaveACounterWithADuplicateNames() { - Counter counter1 = createCounter(project, "TestCounter"); - counterRepository.save(counter1); - Counter counter2 = createCounter(project, "TestCounter"); - - assertThrows(DataIntegrityViolationException.class, () -> counterRepository.save(counter2)); - } - - @Test - public void shouldSaveCountersWithADuplicateNamesInDifferentProjects() { - Project project2 = createProject(user, "Test Project 2"); - project2 = projectRepository.save(project2); - - Counter counter1 = createCounter(project, "TestCounter"); - counterRepository.save(counter1); - Counter counter2 = createCounter(project2, "TestCounter"); - counter2 = counterRepository.save(counter2); - - assertNotNull(counter2.getId()); - } - - @Test - public void shouldFetchAllCountersOfAProject() { - Counter counter1 = createCounter(project, "TestCounter1"); - counter1 = counterRepository.save(counter1); - Counter counter2 = createCounter(project, "TestCounter2"); - counter2 = counterRepository.save(counter2); - - List counters = counterRepository.findAllByProject(project); - - assertEquals(2, counters.size()); - assertTrue(counters.contains(counter1)); - assertTrue(counters.contains(counter2)); - } - - @Test - public void shouldFetchOntCountersOfAProjectByItsName() { - Counter counter = createCounter(project, "TestCounter1"); - counter = counterRepository.save(counter); - - Counter counterFromDB = counterRepository.findByProjectAndName(project, "TestCounter1"); - - assertEquals(counter, counterFromDB); - } - - @Test - public void shouldDeleteACounter() { - Counter counter = createCounter(project, "TestCounter"); - counter = counterRepository.save(counter); - - counterRepository.deleteById(counter.getId()); - - assertEquals(0L, counterRepository.count()); - } - - @Test - public void shouldThrowAnExceptionWhenDeletingAnNonExistingCounter() { - assertThrows(EmptyResultDataAccessException.class, () -> counterRepository.deleteById(-1L)); - } - - private Counter createCounter(Project project, String name) { - Counter counter = new Counter(); - counter.setProject(project); - counter.setName(name); - return counter; - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/LearnerResultRepositoryIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/LearnerResultRepositoryIT.java deleted file mode 100644 index 6d87ef954..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/LearnerResultRepositoryIT.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.repositories; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.learning.repositories.LearnerResultRepository; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.transaction.annotation.Transactional; - -public class LearnerResultRepositoryIT extends AbstractRepositoryIT { - - @Autowired - private LearnerResultRepository learnerResultRepository; - - private User user; - - private Project project; - - @BeforeEach - public void before() { - User user = createUser("alex@test.example"); - this.user = userRepository.save(user); - - Project project = createProject(user, "Test Project 1"); - this.project = projectRepository.save(project); - } - - @Test - public void shouldSaveAValidLearnerResult() { - LearnerResult result = createLearnerResult(project, 0L); - learnerResultRepository.save(result); - - assertNotNull(result.getId()); - } - - @Test - public void shouldFailToSaveALearnerResultWithoutAProject() { - LearnerResult result = createLearnerResult(null, 0L); - assertThrows(DataIntegrityViolationException.class, () -> learnerResultRepository.save(result)); - } - - @Test - public void shouldFailToSaveALearnerResultWithoutATestNo() { - LearnerResult result = createLearnerResult(project, null); - assertThrows(DataIntegrityViolationException.class, () -> learnerResultRepository.save(result)); - } - - @Test - public void shouldFailToSaveALearnerResultWithADuplicateTestNo() { - LearnerResult result1 = createLearnerResult(project, 0L); - learnerResultRepository.save(result1); - LearnerResult result2 = createLearnerResult(project, 0L); - assertThrows(DataIntegrityViolationException.class, () -> learnerResultRepository.save(result2)); - } - - @Test - public void shouldSaveLearnerResultsWithADuplicateTestNoInDifferentProjects() { - Project project2 = createProject(user, "Test Project 2"); - project2 = projectRepository.save(project2); - - LearnerResult result1 = createLearnerResult(project, 0L); - learnerResultRepository.save(result1); - LearnerResult result2 = createLearnerResult(project2, 0L); - - result2 = learnerResultRepository.save(result2); - - assertNotNull(result2.getId()); - } - - @Test - public void shouldFetchAllLearnerResultsOfAProject() { - LearnerResult result1 = createLearnerResult(project, 0L); - learnerResultRepository.save(result1); - LearnerResult result2 = createLearnerResult(project, 1L); - learnerResultRepository.save(result2); - - List results = learnerResultRepository - .findByProject_IdOrderByTestNoAsc(project.getId()); - - assertEquals(2, results.size()); - assertTrue(results.contains(result1)); - assertTrue(results.contains(result2)); - } - - @Test - public void shouldFetchLearnerResultsOfAProjectByTheirTestNo() { - LearnerResult result1 = createLearnerResult(project, 0L); - learnerResultRepository.save(result1); - LearnerResult result2 = createLearnerResult(project, 1L); - learnerResultRepository.save(result2); - LearnerResult result3 = createLearnerResult(project, 2L); - learnerResultRepository.save(result3); - - List results = learnerResultRepository.findByProject_IdAndTestNoIn(project.getId(), Arrays.asList(0L, 2L)); - - assertEquals(2, results.size()); - assertTrue(results.contains(result1)); - assertFalse(results.contains(result2)); - assertTrue(results.contains(result3)); - } - - @Test - public void shouldFetchHighestTestNo() { - LearnerResult result1 = createLearnerResult(project, 0L); - learnerResultRepository.save(result1); - LearnerResult result2 = createLearnerResult(project, 1L); - learnerResultRepository.save(result2); - - Long highestTestNo = learnerResultRepository.findHighestTestNo(project.getId()); - - assertEquals(1L, (long) highestTestNo); - } - - @Test - public void shouldFetchNullAsHighestTestNoIfNoLearnerResultsExists() { - Long highestTestNo = learnerResultRepository.findHighestTestNo(-1L); - - assertNull(highestTestNo); - } - - @Test - @Transactional - public void shouldDeleteALearnerResult() { - LearnerResult result = createLearnerResult(project, 0L); - learnerResultRepository.save(result); - - Long deleteReturnValue = learnerResultRepository.deleteByProject_IdAndTestNoIn( - project.getId(), Collections.singletonList(0L)); - - assertEquals(1L, (long) deleteReturnValue); - assertEquals(0L, learnerResultRepository.count()); - } - - @Test - public void shouldNotDeleteAnNonExistingLearnerResult() { - Long deleteReturnValue = learnerResultRepository.deleteByProject_IdAndTestNoIn( - project.getId(), Collections.singletonList(-1L)); - - assertEquals(0L, (long) deleteReturnValue); - } - - static LearnerResult createLearnerResult(Project project, Long testNo) { - LearnerResult result = new LearnerResult(); - result.setProject(project); - result.setTestNo(testNo); - return result; - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/LearnerResultStepRepositoryIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/LearnerResultStepRepositoryIT.java deleted file mode 100644 index 0f73a05d7..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/LearnerResultStepRepositoryIT.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.repositories; - -import static de.learnlib.alex.integrationtests.repositories.LearnerResultRepositoryIT.createLearnerResult; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.learning.entities.LearnerResultStep; -import de.learnlib.alex.learning.repositories.LearnerResultRepository; -import de.learnlib.alex.learning.repositories.LearnerResultStepRepository; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.DataIntegrityViolationException; - -public class LearnerResultStepRepositoryIT extends AbstractRepositoryIT { - - @Autowired - private LearnerResultRepository learnerResultRepository; - - @Autowired - private LearnerResultStepRepository learnerResultStepRepository; - - private Project project; - - @BeforeEach - public void before() { - User user = createUser("alex@test.example"); - user = userRepository.save(user); - - Project project = createProject(user, "Test Project 1"); - this.project = projectRepository.save(project); - } - - @Test - public void shouldSaveAValidLearnerResultStep() { - LearnerResult result = createLearnerResult(project, 0L); - learnerResultRepository.save(result); - - LearnerResultStep step = createLearnerResultStep(result, 0L); - learnerResultStepRepository.save(step); - - assertNotNull(result.getId()); - } - - @Test - public void shouldFailToSaveALearnerResultStepWithoutALearnerResult() { - LearnerResult result = createLearnerResult(project, 0L); - learnerResultRepository.save(result); - - LearnerResultStep step = createLearnerResultStep(null, 0L); - assertThrows(DataIntegrityViolationException.class, () -> learnerResultStepRepository.save(step)); - } - - @Test - public void shouldFailToSaveALearnerResultStepWithoutAStepNo() { - LearnerResult result = createLearnerResult(project, 0L); - learnerResultRepository.save(result); - - LearnerResultStep step = createLearnerResultStep(result, null); - assertThrows(DataIntegrityViolationException.class, () -> learnerResultStepRepository.save(step)); - } - - @Test - public void shouldFailToSaveALearnerResultStepWithADuplicateStepNo() { - LearnerResult result = createLearnerResult(project, 0L); - learnerResultRepository.save(result); - - LearnerResultStep step1 = createLearnerResultStep(result, 0L); - learnerResultStepRepository.save(step1); - LearnerResultStep step2 = createLearnerResultStep(result, 0L); - assertThrows(DataIntegrityViolationException.class, () -> learnerResultStepRepository.save(step2)); - } - - @Test - public void shouldSaveLearnerResultsWithADuplicateStepNoInDifferentLearnerResults() { - LearnerResult result1 = createLearnerResult(project, 0L); - learnerResultRepository.save(result1); - LearnerResult result2 = createLearnerResult(project, 1L); - result2 = learnerResultRepository.save(result2); - - LearnerResultStep step1 = createLearnerResultStep(result1, 0L); - learnerResultStepRepository.save(step1); - LearnerResultStep step2 = createLearnerResultStep(result2, 0L); - - learnerResultStepRepository.save(step2); - - assertNotNull(result2.getId()); - } - - private LearnerResultStep createLearnerResultStep(LearnerResult result, Long stepNo) { - LearnerResultStep step = new LearnerResultStep(); - step.setResult(result); - step.setStepNo(stepNo); - return step; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/ProjectRepositoryIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/ProjectRepositoryIT.java deleted file mode 100644 index d80d21595..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/ProjectRepositoryIT.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.repositories; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.repositories.SymbolGroupRepository; -import java.util.List; -import javax.validation.ValidationException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.EmptyResultDataAccessException; - -public class ProjectRepositoryIT extends AbstractRepositoryIT { - - @Autowired - private SymbolGroupRepository symbolGroupRepository; - - private User user; - - @BeforeEach - public void before() { - User user = createUser("alex@test.example"); - this.user = userRepository.save(user); - } - - @Test - public void shouldSaveAValidProject() { - Project project = createProject(user, "Test Project"); - project = projectRepository.save(project); - - assertTrue(project.getId() > 0L); - } - - @Test - public void shouldFailToSaveAProjectWithoutAName() { - Project project = new Project(); - project.addOwner(user); - assertThrows(ValidationException.class, () -> projectRepository.save(project)); // should fail - } - - @Test - public void shouldSaveAProjectsWithADuplicateNameForMultipleUsers() { - User otherUser = createUser("foo@test.example"); - otherUser = userRepository.save(otherUser); - - Project project = createProject(user, "Test Project"); - projectRepository.save(project); - Project otherProject = createProject(otherUser, "Test Project"); - - otherProject = projectRepository.save(otherProject); - - assertTrue(otherProject.getId() > 0L); - } - - @Test - public void shouldFetchAllProjectsOfAUser() { - User otherUser = createUser("foo2@test.example"); - otherUser = userRepository.save(otherUser); - - Project project1 = createProject(user, "Test Project 1"); - project1 = projectRepository.save(project1); - Project project2 = createProject(user, "Test Project 2"); - project2 = projectRepository.save(project2); - Project project3 = createProject(otherUser, "Test Project 3"); - projectRepository.save(project3); - - Project project4 = createProject(otherUser, "Test Project 4"); - project4.addMember(user); - project4 = projectRepository.save(project4); - - List projects = projectRepository.findAllByUser_Id(user.getId()); - - assertEquals(3, projects.size()); - assertTrue(projects.contains(project1)); - assertTrue(projects.contains(project2)); - assertTrue(projects.contains(project4)); - } - - @Test - public void shouldReturnEmptyListWhenFetchingAllProjectsOfAUserWhoHasNone() { - List projects = projectRepository.findAllByUser_Id(user.getId()); - - assertEquals(0, projects.size()); - } - - @Test - public void shouldFetchAProjectOfAUserByItsID() { - Project project = createProject(user, "Test Project"); - project = projectRepository.save(project); - - Project projectFromDB = projectRepository.findById(project.getId()).orElse(null); - - assertEquals(project, projectFromDB); - } - - @Test - public void shouldReturnNullWhenFetchingANonExistingProjectOfAUserByItsID() { - Project projectFromDB = projectRepository.findById(-1L).orElse(null); - - assertNull(projectFromDB); - } - - @Test - public void shouldDeleteAProject() { - Project project = createProject(user, "Test Project"); - project = projectRepository.save(project); - - assertEquals(1L, symbolGroupRepository.count()); - - projectRepository.delete(project); - - assertEquals(0L, projectRepository.count()); - assertEquals(0L, symbolGroupRepository.count()); - } - - @Test - public void shouldThrowAnExceptionWhenDeletingAnNonExistingProject() { - assertThrows(EmptyResultDataAccessException.class, () -> projectRepository.deleteById(-1L)); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/SymbolGroupRepositoryIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/SymbolGroupRepositoryIT.java deleted file mode 100644 index 05eaec355..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/SymbolGroupRepositoryIT.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.repositories; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.SymbolGroup; -import de.learnlib.alex.data.repositories.SymbolGroupRepository; -import java.util.List; -import javax.validation.ValidationException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.dao.EmptyResultDataAccessException; - -public class SymbolGroupRepositoryIT extends AbstractRepositoryIT { - - @Autowired - private SymbolGroupRepository symbolGroupRepository; - - private User user; - - private Project project; - - @BeforeEach - public void before() { - User user = createUser("alex@test.example"); - this.user = userRepository.save(user); - - Project project = createProject(user, "Test Project 1"); - this.project = projectRepository.save(project); - } - - @Test - public void shouldSaveAValidGroup() { - SymbolGroup group = createGroup(project, 1L, "Test Group"); - group = symbolGroupRepository.save(group); - - assertTrue(group.getId() > 0L); - } - - @Test - public void shouldFailToSaveAGroupWithoutAProject() { - SymbolGroup group = new SymbolGroup(); - group.setId(1L); - group.setName("Test Group"); - - project.getGroups().add(group); - - assertThrows(DataIntegrityViolationException.class, () -> symbolGroupRepository.save(group)); - } - - @Test - public void shouldFailToSaveAGroupWithoutAName() { - SymbolGroup group = new SymbolGroup(); - group.setProject(project); - project.getGroups().add(group); - group.setId(1L); - - assertThrows(ValidationException.class, () -> symbolGroupRepository.save(group)); - } - - @ParameterizedTest(name = "create groups with names: \"{0}, {1}\"") - @CsvSource({ - "Test Group 1, Test Group 2", - "Test Group, Test Group" - }) - public void shouldSaveGroupsWithADuplicateIDsInDifferentProjects(String groupName1, String groupName2) { - Project project2 = createProject(user, "Test Project 2"); - project2 = projectRepository.save(project2); - - SymbolGroup group1 = createGroup(project, 1L, groupName1); - symbolGroupRepository.save(group1); - SymbolGroup group2 = createGroup(project2, 1L, groupName2); - - final var createdGroup = symbolGroupRepository.save(group2); - - assertNotNull(createdGroup); - assertTrue(createdGroup.getId() > 0L); - } - - @Test - public void shouldFetchAllGroupsOfAProject() { - SymbolGroup group1 = createGroup(project, null, "Test Group 1"); - group1 = symbolGroupRepository.save(group1); - SymbolGroup group2 = createGroup(project, null, "Test Group 2"); - group2 = symbolGroupRepository.save(group2); - - List groups = symbolGroupRepository.findAllByProject_Id(project.getId()); - - assertEquals(3, groups.size()); - assertTrue(groups.contains(group1)); - assertTrue(groups.contains(group2)); - } - - @Test - public void shouldFetchAGroupOfAProjectByItsID() { - SymbolGroup group = createGroup(project, null, "Test Group 1"); - group = symbolGroupRepository.save(group); - - SymbolGroup groupFromDB = symbolGroupRepository.findById(group.getId()).orElse(null); - - assertNotNull(groupFromDB.getProject()); - assertEquals(project, groupFromDB.getProject()); - assertEquals(group.getId(), groupFromDB.getId()); - } - - @Test - public void shouldDeleteAGroup() { - SymbolGroup group = createGroup(project, 1L, "Test Group 1"); - group = symbolGroupRepository.save(group); - - symbolGroupRepository.delete(group); - - assertEquals(1L, symbolGroupRepository.count()); // only default group left - } - - @Test - public void shouldThrowAnExceptionWhenDeletingAnNonExistingGroup() { - assertThrows(EmptyResultDataAccessException.class, () -> symbolGroupRepository.deleteById(-1L)); - } - - static SymbolGroup createGroup(Project project, Long id, String name) { - SymbolGroup group = new SymbolGroup(); - group.setProject(project); - project.getGroups().add(group); - group.setId(id); - group.setName(name); - return group; - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/SymbolRepositoryIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/SymbolRepositoryIT.java deleted file mode 100644 index 40546b062..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/SymbolRepositoryIT.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.repositories; - -import static de.learnlib.alex.integrationtests.repositories.SymbolGroupRepositoryIT.createGroup; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolGroup; -import de.learnlib.alex.data.repositories.SymbolGroupRepository; -import de.learnlib.alex.data.repositories.SymbolRepository; -import java.util.Arrays; -import java.util.List; -import javax.validation.ValidationException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.DataIntegrityViolationException; - -public class SymbolRepositoryIT extends AbstractRepositoryIT { - - @Autowired - private SymbolGroupRepository symbolGroupRepository; - - @Autowired - private SymbolRepository symbolRepository; - - private Project project; - - @BeforeEach - public void before() { - User user = createUser("alex@test.example"); - user = userRepository.save(user); - - Project project = createProject(user, "Test Project 1"); - this.project = projectRepository.save(project); - } - - @Test - public void shouldSaveAValidSymbol() { - SymbolGroup group = createGroup(project, 1L, "Test Group"); - group = symbolGroupRepository.save(group); - - Symbol symbol = createSymbol(project, group, 0L, "Test Symbol"); - symbol = symbolRepository.save(symbol); - - assertNotNull(symbol.getId()); - } - - @Test - public void shouldFailToSaveASymbolWithoutAProject() { - SymbolGroup group = createGroup(project, 1L, "Test Group"); - group = symbolGroupRepository.save(group); - - Symbol symbol = createSymbol(null, group, 0L, "Test Symbol"); - assertThrows(DataIntegrityViolationException.class, () -> symbolRepository.save(symbol)); - } - - @Test - public void shouldFailToSaveASymbolWithoutAGroup() { - Symbol symbol = createSymbol(project, null, 0L, "Test Symbol"); - assertThrows(DataIntegrityViolationException.class, () -> symbolRepository.save(symbol)); - } - - @Test - public void shouldFailToSaveASymbolWithoutAName() { - SymbolGroup group = createGroup(project, 1L, "Test Group"); - group = symbolGroupRepository.save(group); - - Symbol symbol = createSymbol(project, group, 0L, null); - assertThrows(ValidationException.class, () -> symbolRepository.save(symbol)); - } - - @Test - public void shouldFetchOneSymbolById() { - SymbolGroup group = createGroup(project, 1L, "Test Group"); - group = symbolGroupRepository.save(group); - - Symbol s1 = createSymbol(project, group, null, "Test Symbol 1"); - s1 = symbolRepository.save(s1); - Symbol s2 = createSymbol(project, group, null, "Test Symbol 2"); - symbolRepository.save(s2); - - Symbol symbolFromDB = symbolRepository.findById(s1.getId()).orElse(null); - - assertEquals(s1, symbolFromDB); - } - - @Test - public void shouldFetchSymbolsByIds() { - SymbolGroup group = createGroup(project, 1L, "Test Group"); - group = symbolGroupRepository.save(group); - - Symbol s1 = createSymbol(project, group, null, "Test Symbol 1"); - s1 = symbolRepository.save(s1); - Symbol s2 = createSymbol(project, group, null, "Test Symbol 2"); - s2 = symbolRepository.save(s2); - - List symbolsFromDB = symbolRepository.findAllByIdIn(Arrays.asList(s1.getId(), s2.getId())); - - assertEquals(2, symbolsFromDB.size()); - assertTrue(symbolsFromDB.contains(s1)); - assertTrue(symbolsFromDB.contains(s2)); - } - - private Symbol createSymbol(Project project, SymbolGroup group, Long id, String name) { - Symbol symbol = new Symbol(); - symbol.setProject(project); - symbol.setId(id); - symbol.setGroup(group); - symbol.setName(name); - return symbol; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/UserRepositoryIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/UserRepositoryIT.java deleted file mode 100644 index dc58f55a3..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/repositories/UserRepositoryIT.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.repositories; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.auth.entities.UserRole; -import java.util.List; -import java.util.Optional; -import javax.validation.ValidationException; -import org.junit.jupiter.api.Test; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.dao.EmptyResultDataAccessException; - -public class UserRepositoryIT extends AbstractRepositoryIT { - - @Test - public void shouldSaveAValidUser() { - User user = createUser("test_user@test.example"); - userRepository.save(user); - - assertTrue(user.getId() > 1); - } - - @Test - public void shouldFailWhenSavingAnUserWithoutAnEmail() { - User user = new User(); - user.setPassword("password"); - - assertThrows(ValidationException.class, () -> userRepository.save(user)); - } - - - @Test - public void shouldFailWhenSavingAnUserWithAnInvalidEmail() { - User user = new User(); - user.setEmail("test"); - user.setPassword("password"); - - assertThrows(ValidationException.class, () -> userRepository.save(user)); - } - - @Test - public void shouldFailWhenSavingAnUserWithoutPassword() { - User user = new User(); - user.setEmail("test_user@test.example"); - - assertThrows(ValidationException.class, () -> userRepository.save(user)); - } - - @Test - public void shouldFailOnUserSavingIfTheEMailIsAlreadyUsed() { - User user1 = createUser("test_user@test.example"); - userRepository.save(user1); - - User user2 = createUser("test_user@test.example"); - assertThrows(DataIntegrityViolationException.class, () -> userRepository.save(user2)); - } - - @Test - public void shouldFetchAllUsers() { - User user1 = createUser("test_user_1@test.example"); - user1 = userRepository.save(user1); - User user2 = createUser("test_user_2@test.example"); - user2 = userRepository.save(user2); - - List allUsersFromDB = userRepository.findAll(); - - assertEquals(3, allUsersFromDB.size()); // 3 because of the default admin - assertTrue(allUsersFromDB.contains(user1)); - assertTrue(allUsersFromDB.contains(user2)); - } - - @Test - public void shouldReturnAnEmptyListWhenFetchingAllUsersButNoneExists() { - List users = userRepository.findAll(); - - assertEquals(1, users.size()); - } - - @Test - public void shouldFetchAllUsersWithAnRoleOfRegistered() { - User user1 = createUser("test_user_1@test.example"); - user1.setRole(UserRole.ADMIN); - userRepository.save(user1); - User user2 = createUser("test_user_2@test.example"); - userRepository.save(user2); - - List allUsersFromDB = userRepository.findByRole(UserRole.REGISTERED); - - assertEquals(1, allUsersFromDB.size()); - assertTrue(allUsersFromDB.contains(user2)); - } - - @Test - public void shouldFetchAllUsersWithAnRoleOfAdmin() { - User user1 = createUser("test_user_1@test.example"); - user1.setRole(UserRole.ADMIN); - user1 = userRepository.save(user1); - User user2 = createUser("test_user_2@test.example"); - userRepository.save(user2); - - List allUsersFromDB = userRepository.findByRole(UserRole.ADMIN); - - assertEquals(2, allUsersFromDB.size()); - assertTrue(allUsersFromDB.contains(user1)); - } - - @Test - public void shouldFetchAnExistingUserByTheID() { - User user = createUser("test_user@test.example"); - user = userRepository.save(user); - - User userFromDB = userRepository.findById(user.getId()).orElse(null); - - assertNotNull(userFromDB); - assertEquals(user, userFromDB); - } - - @Test - public void shouldReturnNullWhenFetchingANonExistingUsersByTheID() { - User userFromDB = userRepository.findById(-1L).orElse(null); - assertNull(userFromDB); - } - - @Test - public void shouldFetchAnExistingUserByTheEMail() { - User user = createUser("test_user@test.example"); - user = userRepository.save(user); - - Optional userFromDB = userRepository.findOneByEmail(user.getEmail()); - - assertTrue(userFromDB.isPresent()); - assertEquals(user, userFromDB.get()); - } - - @Test - public void shouldReturnNullWhenFetchingANonExistingUsersByTheEMail() { - Optional userFromDB = userRepository.findOneByEmail("test_user@test.example"); - - assertTrue(userFromDB.isEmpty()); - } - - @Test - public void shouldDeleteAnUser() { - User user = createUser("test_user@test.example"); - user = userRepository.save(user); - - userRepository.deleteById(user.getId()); - - assertEquals(1, userRepository.count()); - } - - @Test - public void shouldThrowAnExceptionWhenDeletingAnNonExistingUser() { - assertThrows(EmptyResultDataAccessException.class, () -> userRepository.deleteById(-1L)); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/ATestExecutionConfigResourceIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/ATestExecutionConfigResourceIT.java deleted file mode 100644 index 1b21a68bf..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/ATestExecutionConfigResourceIT.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources; - -import com.jayway.jsonpath.JsonPath; -import de.learnlib.alex.integrationtests.resources.api.ProjectApi; -import de.learnlib.alex.integrationtests.resources.api.TestApi; -import de.learnlib.alex.integrationtests.resources.api.TestExecutionConfigApi; -import de.learnlib.alex.integrationtests.resources.api.UserApi; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import javax.ws.rs.core.Response; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class ATestExecutionConfigResourceIT extends AbstractResourceIT { - - private TestExecutionConfigApi api; - - private String jwtUser1; - - private String jwtUser2; - - private int projectId1; - - private int projectId2; - - private int envId1; - - private int envId2; - - @BeforeEach - public void before() { - this.api = new TestExecutionConfigApi(client, port); - - final UserApi userApi = new UserApi(client, port); - userApi.create("{\"email\":\"user1@alex.com\", \"username\":\"user1\", \"password\":\"password123\"}"); - userApi.create("{\"email\":\"user2@alex.com\", \"username\":\"user2\", \"password\":\"password123\"}"); - this.jwtUser1 = userApi.login("user1@alex.com", "password123"); - this.jwtUser2 = userApi.login("user2@alex.com", "password123"); - - final ProjectApi projectApi = new ProjectApi(client, port); - - final Response res1 = projectApi.create("{\"name\":\"test\",\"url\":\"http://localhost:8080/"}", this.jwtUser1); - final String project1 = res1.readEntity(String.class); - this.projectId1 = JsonPath.read(project1, "$.id"); - this.envId1 = JsonPath.read(project1, "$.environments[0].id"); - - final Response res2 = projectApi.create("{\"name\":\"test\",\"url\":\"http://localhost:8080/"}", this.jwtUser2); - final String project2 = res2.readEntity(String.class); - this.projectId2 = JsonPath.read(project2, "$.id"); - this.envId2 = JsonPath.read(project2, "$.environments[0].id"); - } - - @Test - public void shouldCreateAConfig() throws Exception { - final Response res = api.create(projectId1, createConfig(projectId1, envId1), jwtUser1); - assertEquals(Response.Status.CREATED.getStatusCode(), res.getStatus()); - assertEquals(1, getNumberOfConfigs(projectId1, jwtUser1)); - } - - @Test - public void shouldCreateAConfigWithTests() throws Exception { - final TestApi testApi = new TestApi(client, port); - - final String tc = "{\"name\": \"tc\", \"type\": \"case\"}"; - final Response res1 = testApi.create(projectId1, tc, jwtUser1); - assertEquals(Response.Status.CREATED.getStatusCode(), res1.getStatus()); - - final int tcId = JsonPath.read(res1.readEntity(String.class), "$.id"); - final Response res2 = api.create(projectId1, createConfigWithTests(projectId1, envId1, List.of((long) tcId)), jwtUser1); - assertEquals(Response.Status.CREATED.getStatusCode(), res2.getStatus()); - assertEquals(1, getNumberOfConfigs(projectId1, jwtUser1)); - } - - @Test - public void shouldGetEmptyListIfNoConfigExists() throws Exception { - final Response res = api.getAll(projectId1, jwtUser1); - assertEquals(Response.Status.OK.getStatusCode(), res.getStatus()); - assertEquals("[]", res.readEntity(String.class)); - assertEquals(0, getNumberOfConfigs(projectId1, jwtUser1)); - } - - @Test - public void shouldGetAllConfigs() throws Exception { - api.create(projectId1, createConfig(projectId1, envId1), jwtUser1); - api.create(projectId1, createConfig(projectId1, envId1), jwtUser1); - assertEquals(2, getNumberOfConfigs(projectId1, jwtUser1)); - } - - @Test - public void shouldNotGetConfigsOfAnotherUsersProject() { - final Response res = api.getAll(projectId2, jwtUser1); - assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), res.getStatus()); - JsonPath.read(res.readEntity(String.class), "$.message"); - } - - @Test - public void shouldFailToCreateConfigIfUrlDoesNotExist() throws Exception { - final Response res = api.create(projectId1, createConfig(projectId1, -1), jwtUser1); - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), res.getStatus()); - assertEquals(0, getNumberOfConfigs(projectId1, jwtUser1)); - } - - @Test - public void shouldNotCreateConfigInAnotherUsersProject() throws Exception { - final Response res = api.create(projectId1, createConfig(projectId1, envId1), jwtUser2); - assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), res.getStatus()); - assertEquals(0, getNumberOfConfigs(projectId1, jwtUser1)); - assertEquals(0, getNumberOfConfigs(projectId2, jwtUser2)); - } - - @Test - public void shouldDeleteConfig() throws Exception { - final Response res = api.create(projectId1, createConfig(projectId1, envId1), jwtUser1); - final int id = JsonPath.read(res.readEntity(String.class), "$.id"); - - final Response res2 = api.delete(projectId1, id, jwtUser1); - assertEquals(Response.Status.NO_CONTENT.getStatusCode(), res2.getStatus()); - assertEquals(0, getNumberOfConfigs(projectId1, jwtUser1)); - } - - @Test - public void shouldFailToDeleteIfConfigDoesNotExist() throws Exception { - final Response res = api.delete(projectId1, -1, jwtUser1); - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), res.getStatus()); - assertEquals(0, getNumberOfConfigs(projectId1, jwtUser1)); - } - - @Test - public void shouldFailToDeleteConfigOfAnotherUser() throws Exception { - final Response res = api.create(projectId1, createConfig(projectId1, envId1), jwtUser1); - final int id = JsonPath.read(res.readEntity(String.class), "$.id"); - - final Response res2 = api.delete(projectId1, id, jwtUser2); - assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), res2.getStatus()); - assertEquals(1, getNumberOfConfigs(projectId1, jwtUser1)); - } - - private int getNumberOfConfigs(int projectId1, String jwt) throws Exception { - final Response res = api.getAll(projectId1, jwt); - return objectMapper.readTree(res.readEntity(String.class)).size(); - } - - private String createConfig(int projectId, int envId) { - return "{" - + "\"tests\":[]" - + ",\"driverConfig\":{\"browser\":\"chrome\"}" - + ",\"environmentId\":" + envId - + ",\"project\":" + projectId - + "}"; - } - - private String createConfigWithTests(int projectId, int envId, List testIds) { - return "{" - + "\"tests\":" + testIds.toString() - + ",\"driverConfig\":{\"browser\":\"chrome\"}" - + ",\"environmentId\":" + envId - + ",\"project\":" + projectId - + "}"; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/ATestResourceIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/ATestResourceIT.java deleted file mode 100644 index ef503031d..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/ATestResourceIT.java +++ /dev/null @@ -1,806 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources; - -import static org.awaitility.Awaitility.await; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.jayway.jsonpath.JsonPath; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.integrationtests.SpringRestError; -import de.learnlib.alex.integrationtests.resources.api.ProjectApi; -import de.learnlib.alex.integrationtests.resources.api.SymbolApi; -import de.learnlib.alex.integrationtests.resources.api.TestApi; -import de.learnlib.alex.integrationtests.resources.api.TestReportApi; -import de.learnlib.alex.integrationtests.resources.api.UserApi; -import de.learnlib.alex.integrationtests.resources.utils.SymbolUtils; -import de.learnlib.alex.integrationtests.websocket.util.TestPresenceServiceWSMessages; -import de.learnlib.alex.integrationtests.websocket.util.WebSocketUser; -import de.learnlib.alex.learning.entities.WebDriverConfig; -import de.learnlib.alex.testing.entities.TestCase; -import de.learnlib.alex.testing.entities.TestCaseResult; -import de.learnlib.alex.testing.entities.TestCaseStep; -import de.learnlib.alex.testing.entities.TestExecutionConfig; -import de.learnlib.alex.testing.entities.TestExecutionResult; -import de.learnlib.alex.testing.entities.TestQueueItem; -import de.learnlib.alex.testing.entities.TestReport; -import de.learnlib.alex.testing.entities.TestSuite; -import de.learnlib.alex.testing.entities.TestSuiteResult; -import java.time.Duration; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.TimeUnit; -import javax.ws.rs.core.Response; -import org.awaitility.Awaitility; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.http.HttpStatus; - -public class ATestResourceIT extends AbstractResourceIT { - - private final Duration defaultWaitTime = Duration.ofSeconds(5); - - private TestApi testApi; - private SymbolApi symbolApi; - private TestReportApi testReportApi; - private SymbolUtils symbolUtils; - - private String jwtUser1; - private String jwtUser2; - - private int userId1; - private int userId2; - - private Project project; - private int projectId; - - private int rootTestSuiteId; - - private ProjectApi projectApi; - - private TestPresenceServiceWSMessages testPresenceServiceWSMessages; - - @BeforeEach - public void pre() { - this.testApi = new TestApi(client, port); - this.testPresenceServiceWSMessages = new TestPresenceServiceWSMessages(); - - final UserApi userApi = new UserApi(client, port); - final Response res1 = userApi.create("{\"email\":\"test1@test.de\", \"username\":\"test1\", \"password\":\"test\"}"); - final Response res2 = userApi.create("{\"email\":\"test2@test.de\", \"username\":\"test2\", \"password\":\"test\"}"); - - userId1 = res1.readEntity(User.class).getId().intValue(); - userId2 = res2.readEntity(User.class).getId().intValue(); - - jwtUser1 = userApi.login("test1@test.de", "test"); - jwtUser2 = userApi.login("test2@test.de", "test"); - - projectApi = new ProjectApi(client, port); - final Response res3 = projectApi.create("{\"name\":\"test\",\"url\":\"http://localhost:8080/"}", jwtUser1); - project = res3.readEntity(Project.class); - projectId = project.getId().intValue(); - - symbolApi = new SymbolApi(client, port); - symbolUtils = new SymbolUtils(symbolApi); - - testReportApi = new TestReportApi(client, port); - - final SymbolApi symbolApi = new SymbolApi(client, port); - symbolApi.create(projectId, "{\"name\":\"s1\"}", jwtUser1); - symbolApi.create(projectId, "{\"name\":\"s2\"}", jwtUser1); - - final Response res4 = testApi.getRoot(projectId, jwtUser1); - this.rootTestSuiteId = JsonPath.read(res4.readEntity(String.class), "$.id"); - } - - @Test - public void shouldCreateATestCase() { - final String tc = "{\"name\": \"tc\", \"type\": \"case\"}"; - final Response res = testApi.create(projectId, tc, jwtUser1); - assertEquals(Response.Status.CREATED.getStatusCode(), res.getStatus()); - - final String tcRes = res.readEntity(String.class); - assertEquals("case", JsonPath.read(tcRes, "$.type")); // is test case? - assertEquals(Integer.valueOf(rootTestSuiteId), JsonPath.read(tcRes, "$.parent")); // created in root? - assertEquals(Integer.valueOf(projectId), JsonPath.read(tcRes, "$.project")); - } - - @Test - public void shouldCreateATestSuite() { - final String ts = "{\"name\": \"ts\", \"type\": \"suite\"}"; - final Response res = testApi.create(projectId, ts, jwtUser1); - assertEquals(Response.Status.CREATED.getStatusCode(), res.getStatus()); - - final String tsRes = res.readEntity(String.class); - assertEquals("suite", JsonPath.read(tsRes, "$.type")); // is test suite? - assertEquals(Integer.valueOf(rootTestSuiteId), JsonPath.read(tsRes, "$.parent")); // created in root? - assertEquals(Integer.valueOf(projectId), JsonPath.read(tsRes, "$.project")); - assertEquals("[]", JsonPath.read(tsRes, "$.tests").toString()); - } - - @Test - public void shouldCreateTestCaseInTestSuite() throws Exception { - final String ts = "{\"name\": \"ts\", \"type\": \"suite\"}"; - final Response res1 = testApi.create(projectId, ts, jwtUser1); - final int tsId = JsonPath.read(res1.readEntity(String.class), "$.id"); - - final String tc = "{\"name\": \"tc\", \"type\": \"suite\", \"parent\": " + tsId + "}"; - final Response res2 = testApi.create(projectId, tc, jwtUser1); - assertEquals(Response.Status.CREATED.getStatusCode(), res2.getStatus()); - - final String tcRes = res2.readEntity(String.class); - assertEquals(Integer.valueOf(tsId), JsonPath.read(tcRes, "$.parent")); // correct parent? - - final Response res3 = testApi.get(projectId, tsId, jwtUser1); - final JsonNode tsNode = objectMapper.readTree(res3.readEntity(String.class)); - assertEquals(tcRes, tsNode.get("tests").get(0).toString()); // test case in suite? - } - - @Test - public void shouldCreateTestSuiteInTestSuite() throws Exception { - final String ts1 = "{\"name\": \"ts\", \"type\": \"suite\"}"; - final Response res1 = testApi.create(projectId, ts1, jwtUser1); - final int ts1Id = JsonPath.read(res1.readEntity(String.class), "$.id"); - - final String ts2 = "{\"name\": \"ts\", \"type\": \"suite\", \"parent\": " + ts1Id + "}"; - final Response res2 = testApi.create(projectId, ts2, jwtUser1); - assertEquals(Response.Status.CREATED.getStatusCode(), res2.getStatus()); - - final String ts2Res = res2.readEntity(String.class); - assertEquals(Integer.valueOf(ts1Id), JsonPath.read(ts2Res, "$.parent")); // correct parent? - - final Response res3 = testApi.get(projectId, ts1Id, jwtUser1); - final JsonNode ts1Node = objectMapper.readTree(res3.readEntity(String.class)); - assertEquals(ts2Res, ts1Node.get("tests").get(0).toString()); // test case in suite? - } - - @Test - public void shouldFailToCreateTestWithInvalidParent() throws Exception { - final String tc = "{\"name\": \"tc\", \"type\": \"case\", \"parent\": -1}"; - final Response res1 = testApi.create(projectId, tc, jwtUser1); - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), res1.getStatus()); - - final Response res2 = testApi.getRoot(projectId, jwtUser1); - final JsonNode rootTsNode = objectMapper.readTree(res2.readEntity(String.class)); - assertEquals("[]", rootTsNode.get("tests").toString()); // no test case created? - } - - @Test - public void shouldIncrementNameOfTestIfNameExistsInTestSuite() { - final String tc1 = "{\"name\": \"tc\", \"type\": \"case\"}"; - testApi.create(projectId, tc1, jwtUser1); - - final Response res1 = testApi.create(projectId, tc1, jwtUser1); - assertEquals(Response.Status.CREATED.getStatusCode(), res1.getStatus()); - assertEquals("tc - 1", JsonPath.read(res1.readEntity(String.class), "$.name")); - - final Response res2 = testApi.create(projectId, tc1, jwtUser1); - assertEquals(Response.Status.CREATED.getStatusCode(), res2.getStatus()); - assertEquals("tc - 2", JsonPath.read(res2.readEntity(String.class), "$.name")); - } - - @Test - public void shouldCreateTests() throws Exception { - final String tests = "[" - + "{\"name\": \"tc1\", \"type\": \"case\"}" - + ",{\"name\": \"tc2\", \"type\": \"case\"}" - + ",{\"name\": \"ts\", \"type\": \"suite\"}]"; - - final Response res1 = testApi.createMany(projectId, tests, jwtUser1); - assertEquals(Response.Status.CREATED.getStatusCode(), res1.getStatus()); - - final Response res2 = testApi.getRoot(projectId, jwtUser1); - final JsonNode rootNode = objectMapper.readTree(res2.readEntity(String.class)); - assertEquals(3, rootNode.get("tests").size()); - } - - @Test - public void shouldFailToCreateTestsIfOneCannotBeCreated() throws Exception { - final String tests = "[" - + "{\"name\": \"tc1\", \"type\": \"case\"}" - + ",{\"name\": \"tc2\", \"type\": \"case\", \"parent\": -1}" - + ",{\"name\": \"ts\", \"type\": \"suite\"}]"; - - final Response res1 = testApi.createMany(projectId, tests, jwtUser1); - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), res1.getStatus()); - - final Response res2 = testApi.getRoot(projectId, jwtUser1); - final JsonNode rootNode = objectMapper.readTree(res2.readEntity(String.class)); - assertEquals(0, rootNode.get("tests").size()); - } - - @Test - public void shouldGetTest() { - final String tc = "{\"name\": \"tc\", \"type\": \"case\"}"; - final Response res1 = testApi.create(projectId, tc, jwtUser1); - final String tcRes = res1.readEntity(String.class); - - final Response res2 = testApi.get(projectId, JsonPath.read(tcRes, "$.id"), jwtUser1); - assertEquals(Response.Status.OK.getStatusCode(), res2.getStatus()); - assertEquals(tcRes, res2.readEntity(String.class)); - } - - @Test - public void shouldFailToGetUnknownTest() { - final Response res = testApi.get(projectId, -1, jwtUser1); - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), res.getStatus()); - } - - @Test - public void shouldUpdateTest() throws Exception { - final String tc = "{\"name\": \"tc\", \"type\": \"case\"}"; - final Response res1 = testApi.create(projectId, tc, jwtUser1); - - final TestCase testCase = res1.readEntity(TestCase.class); - testCase.setName("abc"); - - final Response res2 = testApi.update(testCase.getProjectId(), testCase.getId(), objectMapper.writeValueAsString(testCase), jwtUser1); - assertEquals(Response.Status.OK.getStatusCode(), res2.getStatus()); - - // get updated test case - final TestCase updatedTestCase = res2.readEntity(TestCase.class); - assertEquals(testCase.getName(), updatedTestCase.getName()); - - // updated test case is in db - final TestCase testCaseIdDb = testApi.get(projectId, testCase.getId().intValue(), jwtUser1) - .readEntity(TestCase.class); - assertEquals(testCase.getName(), testCaseIdDb.getName()); - } - - @Test - public void shouldUpdateTestMoveStepToPreSteps() throws Exception { - final var testCase = createTestCaseWithSteps(project.getId(), "test", null, jwtUser1); - - final var step = testCase.getSteps().remove(0); - testCase.getPreSteps().add(step); - - final var res = testApi.update(testCase.getProjectId(), testCase.getId(), objectMapper.writeValueAsString(testCase), jwtUser1); - assertEquals(HttpStatus.OK.value(), res.getStatus()); - - final var updatedTestCase = res.readEntity(TestCase.class); - assertAll( - () -> assertEquals(2, updatedTestCase.getPreSteps().size()), - () -> assertEquals(1, updatedTestCase.getSteps().size()), - () -> assertEquals(0, updatedTestCase.getPostSteps().size()) - ); - } - - @Test - public void shouldUpdateTestMoveStepToPostSteps() throws Exception { - final var testCase = createTestCaseWithSteps(project.getId(), "test", null, jwtUser1); - - final var step = testCase.getSteps().remove(0); - testCase.getPostSteps().add(step); - - final var res = testApi.update(testCase.getProjectId(), testCase.getId(), objectMapper.writeValueAsString(testCase), jwtUser1); - assertEquals(HttpStatus.OK.value(), res.getStatus()); - - final var updatedTestCase = res.readEntity(TestCase.class); - assertAll( - () -> assertEquals(1, updatedTestCase.getPreSteps().size()), - () -> assertEquals(1, updatedTestCase.getSteps().size()), - () -> assertEquals(1, updatedTestCase.getPostSteps().size()) - ); - } - - @Test - public void shouldUpdateTestLockedByUser() throws Exception { - WebSocketUser webSocketUser = new WebSocketUser("webSocketUser", client, port); - projectApi.addMembers(Integer.toUnsignedLong(projectId), Collections.singletonList(webSocketUser.getUserId()), jwtUser1); - - final String tc = "{\"name\": \"tc\", \"type\": \"case\"}"; - final Response res1 = testApi.create(projectId, tc, jwtUser1); - - final TestCase testCase = res1.readEntity(TestCase.class); - - // lock testcase - webSocketUser.send("default", testPresenceServiceWSMessages.userEnteredTest(projectId, testCase.getId())); - Awaitility.await().atMost(defaultWaitTime).until(() -> webSocketUser.assertNumberOfMessages(List.of("default"), List.of(1))); - - testCase.setName("abc"); - - final Response res2 = testApi.update(testCase.getProjectId(), testCase.getId(), objectMapper.writeValueAsString(testCase), webSocketUser.getJwt()); - assertEquals(Response.Status.OK.getStatusCode(), res2.getStatus()); - - webSocketUser.forceDisconnectAll(); - } - - @Test - public void shouldFailToUpdateTestLockedByOtherUser() throws Exception { - WebSocketUser webSocketUser = new WebSocketUser("webSocketUser", client, port); - projectApi.addMembers(Integer.toUnsignedLong(projectId), Collections.singletonList(webSocketUser.getUserId()), jwtUser1); - - final String tc = "{\"name\": \"tc\", \"type\": \"case\"}"; - final Response res1 = testApi.create(projectId, tc, jwtUser1); - - final TestCase testCase = res1.readEntity(TestCase.class); - - // lock testcase - webSocketUser.send("default", testPresenceServiceWSMessages.userEnteredTest(projectId, testCase.getId())); - Awaitility.await().atMost(defaultWaitTime).until(() -> webSocketUser.assertNumberOfMessages(List.of("default"), List.of(1))); - - testCase.setName("abc"); - - final Response res2 = testApi.update(testCase.getProjectId(), testCase.getId(), objectMapper.writeValueAsString(testCase), webSocketUser.getJwt()); - assertEquals(Response.Status.OK.getStatusCode(), res2.getStatus()); - - // get updated test case - final TestCase updatedTestCase = res2.readEntity(TestCase.class); - assertEquals(testCase.getName(), updatedTestCase.getName()); - - // updated test case is in db - final TestCase testCaseIdDb = testApi.get(projectId, testCase.getId().intValue(), jwtUser1) - .readEntity(TestCase.class); - assertEquals(testCase.getName(), testCaseIdDb.getName()); - - webSocketUser.forceDisconnectAll(); - } - - @Test - public void shouldUpdateLastUpdatedByOnUpdate() throws JsonProcessingException { - projectApi.addOwners((long) projectId, Collections.singletonList((long) userId2), jwtUser1); - - final String tc = "{\"name\": \"tc\", \"type\": \"case\"}"; - final Response res1 = testApi.create(projectId, tc, jwtUser1); - - final TestCase testCase = res1.readEntity(TestCase.class); - - final Response res2 = testApi.update(testCase.getProjectId(), testCase.getId(), objectMapper.writeValueAsString(testCase), jwtUser2); - assertEquals(Response.Status.OK.getStatusCode(), res2.getStatus()); - - final TestCase updatedTestCase = res2.readEntity(TestCase.class); - assertEquals((long) updatedTestCase.getLastUpdatedBy().getId(), userId2); - } - - @Test - public void shouldCreateTestWithSameNameInDifferentTestSuites() throws Exception { - TestSuite ts1 = createTestSuite((long) projectId, "ts1", null, jwtUser1); - TestSuite ts2 = createTestSuite((long) projectId, "ts2", null, jwtUser1); - - final TestCase tc1 = new TestCase(); - tc1.setName("tc"); - tc1.setProjectId((long) projectId); - tc1.setParent(ts1); - testApi.create(projectId, objectMapper.writeValueAsString(tc1), jwtUser1); - tc1.setParent(ts2); - testApi.create(projectId, objectMapper.writeValueAsString(tc1), jwtUser1); - - ts1 = testApi.get(projectId, ts1.getId().intValue(), jwtUser1).readEntity(TestSuite.class); - ts2 = testApi.get(projectId, ts2.getId().intValue(), jwtUser1).readEntity(TestSuite.class); - - assertEquals(1, ts1.getTestCases().size()); - assertEquals(1, ts2.getTestCases().size()); - assertEquals("tc", ts1.getTestCases().get(0).getName()); - assertEquals("tc", ts2.getTestCases().get(0).getName()); - } - - @Test - public void shouldMoveTestCase() throws Exception { - TestSuite ts1 = createTestSuite((long) projectId, "ts1", null, jwtUser1); - TestCase tc = createTestCase((long) projectId, "tc", null, jwtUser1); - - final Response res3 = testApi.move(projectId, tc.getId().intValue(), ts1.getId().intValue(), jwtUser1); - assertEquals(HttpStatus.OK.value(), res3.getStatus()); - - ts1 = testApi.get(projectId, ts1.getId().intValue(), jwtUser1).readEntity(TestSuite.class); - tc = testApi.get(projectId, tc.getId().intValue(), jwtUser1).readEntity(TestCase.class); - - assertEquals(ts1.getId(), tc.getParent().getId()); - assertEquals(1, ts1.getTestCases().size()); - assertEquals(tc.getId(), ts1.getTestCases().get(0).getId()); - } - - @Test - public void shouldMoveTestSuite() throws Exception { - TestSuite ts1 = createTestSuite((long) projectId, "ts1", null, jwtUser1); - TestSuite ts2 = createTestSuite((long) projectId, "ts2", null, jwtUser1); - - final Response res3 = testApi.move(projectId, ts1.getId().intValue(), ts2.getId().intValue(), jwtUser1); - assertEquals(HttpStatus.OK.value(), res3.getStatus()); - - ts1 = testApi.get(projectId, ts1.getId().intValue(), jwtUser1).readEntity(TestSuite.class); - ts2 = testApi.get(projectId, ts2.getId().intValue(), jwtUser1).readEntity(TestSuite.class); - - assertEquals(ts2.getId(), ts1.getParentId()); - assertEquals(1, ts2.getTestSuites().size()); - assertEquals(ts1.getId(), ts2.getTestSuites().get(0).getId()); - } - - @Test - public void shouldNotMoveRootTestSuite() throws Exception { - final String ts = "{\"name\": \"ts\", \"type\": \"suite\"}"; - final Response res1 = testApi.create(projectId, ts, jwtUser1); - final int id = JsonPath.read(res1.readEntity(String.class), "$.id"); - - final Response res2 = testApi.move(projectId, rootTestSuiteId, id, jwtUser1); - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), res2.getStatus()); - - final Response res3 = testApi.getRoot(projectId, jwtUser1); - assertTrue(objectMapper.readTree(res3.readEntity(String.class)).get("parent").isNull()); - } - - @Test - public void shouldFailToMoveTestToNonExistingTestSuite() { - final String ts = "{\"name\": \"ts\", \"type\": \"suite\"}"; - final Response res1 = testApi.create(projectId, ts, jwtUser1); - final int id = JsonPath.read(res1.readEntity(String.class), "$.id"); - - final Response res2 = testApi.move(projectId, id, -1, jwtUser1); - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), res2.getStatus()); - } - - @Test - public void shouldNotMoveTestSuiteToItsDescendant() throws Exception { - TestSuite ts1 = createTestSuite((long) projectId, "ts1", null, jwtUser1); - TestSuite ts2 = createTestSuite((long) projectId, "ts2", ts1.getId(), jwtUser1); - - final Response res = testApi.move(projectId, ts1.getId().intValue(), ts2.getId().intValue(), jwtUser1); - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - res.readEntity(SpringRestError.class); - - ts1 = testApi.get(projectId, ts1.getId().intValue(), jwtUser1).readEntity(TestSuite.class); - ts2 = testApi.get(projectId, ts2.getId().intValue(), jwtUser1).readEntity(TestSuite.class); - TestSuite root = testApi.getRoot(projectId, jwtUser1).readEntity(TestSuite.class); - - assertEquals(root.getId(), ts1.getParentId()); - assertEquals(ts1.getId(), ts2.getParentId()); - } - - @Test - public void shouldNotMoveTestToTestCase() throws Exception { - TestCase tc1 = createTestCase((long) projectId, "tc1", null, jwtUser1); - TestCase tc2 = createTestCase((long) projectId, "tc2", null, jwtUser1); - - final Response res = testApi.move(projectId, tc1.getId().intValue(), tc2.getId().intValue(), jwtUser1); - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - res.readEntity(SpringRestError.class); - - tc1 = testApi.get(projectId, tc1.getId().intValue(), jwtUser1).readEntity(TestCase.class); - tc2 = testApi.get(projectId, tc2.getId().intValue(), jwtUser1).readEntity(TestCase.class); - - final TestSuite root = testApi.getRoot(projectId, jwtUser1).readEntity(TestSuite.class); - assertEquals(root.getId(), tc1.getParentId()); - assertEquals(root.getId(), tc2.getParentId()); - assertEquals(2, root.getTestCases().size()); - } - - @Test - public void shouldNotMoveTestToItself() throws Exception { - TestCase tc1 = createTestCase((long) projectId, "tc1", null, jwtUser1); - - final Response res = testApi.move(projectId, tc1.getId().intValue(), tc1.getId().intValue(), jwtUser1); - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - res.readEntity(SpringRestError.class); - - tc1 = testApi.get(projectId, tc1.getId().intValue(), jwtUser1).readEntity(TestCase.class); - - final TestSuite root = testApi.getRoot(projectId, jwtUser1).readEntity(TestSuite.class); - assertEquals(root.getId(), tc1.getParentId()); - assertEquals(1, root.getTestCases().size()); - } - - @Test - public void shouldNotMoveLockedTestCase() throws Exception { - WebSocketUser webSocketUser = new WebSocketUser("webSocketUser", client, port); - projectApi.addMembers(Integer.toUnsignedLong(projectId), Collections.singletonList(webSocketUser.getUserId()), jwtUser1); - - TestSuite ts1 = createTestSuite((long) projectId, "ts1", null, jwtUser1); - TestSuite ts2 = createTestSuite((long) projectId, "ts2", null, jwtUser1); - TestCase tc1 = createTestCase((long) projectId, "tc1", ts1.getId(), jwtUser1); - - // lock testcase - webSocketUser.send("default", testPresenceServiceWSMessages.userEnteredTest(projectId, tc1.getId())); - Awaitility.await().atMost(defaultWaitTime).until(() -> webSocketUser.assertNumberOfMessages(List.of("default"), List.of(1))); - - final Response res = testApi.move(projectId, tc1.getId().intValue(), ts2.getId().intValue(), webSocketUser.getJwt()); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res.getStatus()); - - webSocketUser.forceDisconnectAll(); - } - - @Test - public void shouldNotMoveLockedTestSuite() throws Exception { - WebSocketUser webSocketUser = new WebSocketUser("webSocketUser", client, port); - projectApi.addMembers(Integer.toUnsignedLong(projectId), Collections.singletonList(webSocketUser.getUserId()), jwtUser1); - - TestSuite ts1 = createTestSuite((long) projectId, "ts1", null, jwtUser1); - TestSuite ts2 = createTestSuite((long) projectId, "ts2", null, jwtUser1); - TestCase tc1 = createTestCase((long) projectId, "tc1", ts1.getId(), jwtUser1); - - // lock testcase - webSocketUser.send("default", testPresenceServiceWSMessages.userEnteredTest(projectId, tc1.getId())); - Awaitility.await().atMost(defaultWaitTime).until(() -> webSocketUser.assertNumberOfMessages(List.of("default"), List.of(1))); - - final Response res = testApi.move(projectId, ts1.getId().intValue(), ts2.getId().intValue(), webSocketUser.getJwt()); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res.getStatus()); - - webSocketUser.forceDisconnectAll(); - } - - @Test - public void shouldDeleteTestCase() throws Exception { - final String tc1 = "{\"name\": \"tc1\", \"type\": \"case\"}"; - final Response res1 = testApi.create(projectId, tc1, jwtUser1); - final int id = JsonPath.read(res1.readEntity(String.class), "$.id"); - - final Response res2 = testApi.delete(projectId, id, jwtUser1); - assertEquals(Response.Status.NO_CONTENT.getStatusCode(), res2.getStatus()); - assertEquals(0, getNumberOfTestsInRoot()); - } - - @Test - public void shouldNotDeleteRootTestSuite() { - final Response res1 = testApi.delete(projectId, rootTestSuiteId, jwtUser1); - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), res1.getStatus()); - - final Response res2 = testApi.getRoot(projectId, jwtUser1); - assertEquals(Response.Status.OK.getStatusCode(), res2.getStatus()); - } - - @Test - public void shouldDeleteMultipleTests() throws Exception { - final String tc1 = "{\"name\": \"tc1\", \"type\": \"case\"}"; - final Response res1 = testApi.create(projectId, tc1, jwtUser1); - final int tc1Id = JsonPath.read(res1.readEntity(String.class), "$.id"); - - final String tc2 = "{\"name\": \"tc2\", \"type\": \"case\"}"; - final Response res2 = testApi.create(projectId, tc2, jwtUser1); - final int tc2Id = JsonPath.read(res2.readEntity(String.class), "$.id"); - - final Response res3 = testApi.deleteMany(projectId, Arrays.asList(tc1Id, tc2Id), jwtUser1); - assertEquals(Response.Status.NO_CONTENT.getStatusCode(), res3.getStatus()); - assertEquals(0, getNumberOfTestsInRoot()); - } - - @Test - public void shouldNotDeleteMultipleTestsIfOneFails() throws Exception { - final String tc1 = "{\"name\": \"tc1\", \"type\": \"case\"}"; - final Response res1 = testApi.create(projectId, tc1, jwtUser1); - final int tc1Id = JsonPath.read(res1.readEntity(String.class), "$.id"); - - final Response res2 = testApi.deleteMany(projectId, Arrays.asList(tc1Id, -1), jwtUser1); - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), res2.getStatus()); - assertEquals(1, getNumberOfTestsInRoot()); - } - - @Test - public void shouldNotDeleteLockedTestCase() throws Exception { - WebSocketUser webSocketUser = new WebSocketUser("webSocketUser", client, port); - projectApi.addMembers(Integer.toUnsignedLong(projectId), Collections.singletonList(webSocketUser.getUserId()), jwtUser1); - - TestCase tc1 = createTestCase((long) projectId, "tc1", null, jwtUser1); - - // lock testcase - webSocketUser.send("default", testPresenceServiceWSMessages.userEnteredTest(projectId, tc1.getId())); - Awaitility.await().atMost(defaultWaitTime).until(() -> webSocketUser.assertNumberOfMessages(List.of("default"), List.of(1))); - - final Response res = testApi.delete(projectId, tc1.getId().intValue(), webSocketUser.getJwt()); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res.getStatus()); - - webSocketUser.forceDisconnectAll(); - } - - @Test - public void shouldNotDeleteLockedTestSuite() throws Exception { - WebSocketUser webSocketUser = new WebSocketUser("webSocketUser", client, port); - projectApi.addMembers(Integer.toUnsignedLong(projectId), Collections.singletonList(webSocketUser.getUserId()), jwtUser1); - - TestSuite ts1 = createTestSuite((long) projectId, "ts1", null, jwtUser1); - TestCase tc1 = createTestCase((long) projectId, "tc1", ts1.getId(), jwtUser1); - - // lock testcase - webSocketUser.send("default", testPresenceServiceWSMessages.userEnteredTest(projectId, tc1.getId())); - Awaitility.await().atMost(defaultWaitTime).until(() -> webSocketUser.assertNumberOfMessages(List.of("default"), List.of(1))); - - final Response res = testApi.delete(projectId, ts1.getId().intValue(), webSocketUser.getJwt()); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res.getStatus()); - - webSocketUser.forceDisconnectAll(); - } - - @Test - public void shouldCreateTestWithSteps() throws Exception { - createTestCaseWithSteps(project.getId(), "test", null, jwtUser1); - } - - @Test - public void shouldExecuteTest() throws Exception { - objectMapper.addMixIn(TestReport.class, IgnoreTestReportFieldsMixin.class); - objectMapper.addMixIn(TestExecutionResult.class, IgnoreTestExecutionResultFieldsMixin.class); - objectMapper.addMixIn(TestCaseResult.class, IgnoreTestCaseResultFieldsMixin.class); - - final var testCase = createTestCaseWithSteps(project.getId(), "test", null, jwtUser1); - - final var driverConfig = new WebDriverConfig(); - driverConfig.setBrowser("chrome"); - - final var config = new TestExecutionConfig(); - config.setDriverConfig(driverConfig); - config.setProject(project); - config.setEnvironment(project.getDefaultEnvironment()); - config.setTests(List.of(testCase)); - - final var res1 = testApi.execute(project.getId(), config, jwtUser1); - assertEquals(HttpStatus.OK.value(), res1.getStatus()); - - final var item = objectMapper.readValue(res1.readEntity(String.class), TestQueueItem.class); - assertNotNull(item); - assertNotNull(item.getConfig()); - assertNotNull(item.getReport()); - assertNotNull(item.getResults()); - - var report = pollForTestReport(item.getReport().getId(), jwtUser1); - assertEquals(TestReport.Status.FINISHED, report.getStatus()); - assertTrue(report.getTestResults().size() > 0); - } - - @Test - public void shouldExecuteTestSuite() throws Exception { - objectMapper.addMixIn(TestReport.class, IgnoreTestReportFieldsMixin.class); - objectMapper.addMixIn(TestExecutionResult.class, IgnoreTestExecutionResultFieldsMixin.class); - objectMapper.addMixIn(TestCaseResult.class, IgnoreTestCaseResultFieldsMixin.class); - objectMapper.addMixIn(TestSuiteResult.class, IgnoreTestSuiteResultFieldsMixin.class); - - final var testSuite = createTestSuite(project.getId(), "testSuite", null, jwtUser1); - createTestCaseWithSteps(project.getId(), "test", testSuite.getId(), jwtUser1); - - final var driverConfig = new WebDriverConfig(); - driverConfig.setBrowser("chrome"); - - final var config = new TestExecutionConfig(); - config.setDriverConfig(driverConfig); - config.setProject(project); - config.setEnvironment(project.getDefaultEnvironment()); - config.setTests(List.of(testSuite)); - - final var res1 = testApi.execute(project.getId(), config, jwtUser1); - assertEquals(HttpStatus.OK.value(), res1.getStatus()); - - final var item = objectMapper.readValue(res1.readEntity(String.class), TestQueueItem.class); - assertNotNull(item); - assertNotNull(item.getConfig()); - assertNotNull(item.getReport()); - assertNotNull(item.getResults()); - - var report = pollForTestReport(item.getReport().getId(), jwtUser1); - assertEquals(TestReport.Status.FINISHED, report.getStatus()); - assertTrue(report.getTestResults().size() > 0); - } - - private TestReport pollForTestReport(Long reportId, String jwt) throws JsonProcessingException { - await().atMost(10, TimeUnit.SECONDS).until(() -> { - final var res2 = testReportApi.get(project.getId(), reportId, jwt); - assertEquals(HttpStatus.OK.value(), res2.getStatus()); - - final var report = objectMapper.readValue(res2.readEntity(String.class), TestReport.class); - return List.of(TestReport.Status.ABORTED, TestReport.Status.FINISHED).contains(report.getStatus()); - }); - - final var res = testReportApi.get(project.getId(), reportId, jwt); - return objectMapper.readValue(res.readEntity(String.class), TestReport.class); - } - - private int getNumberOfTestsInRoot() throws Exception { - final Response res = testApi.getRoot(projectId, jwtUser1); - final JsonNode rootNode = objectMapper.readTree(res.readEntity(String.class)); - return rootNode.get("tests").size(); - } - - private TestSuite createTestSuite(Long projectId, String name, Long parentId, String jwt) throws Exception { - final TestSuite ts = new TestSuite(); - ts.setName(name); - ts.setProjectId(projectId); - ts.setParentId(parentId); - - final Response res = testApi.create(projectId.intValue(), objectMapper.writeValueAsString(ts), jwt); - assertEquals(HttpStatus.CREATED.value(), res.getStatus()); - return res.readEntity(TestSuite.class); - } - - private TestCase createTestCase(Long projectId, String name, Long parentId, String jwt) throws Exception { - final TestCase tc = new TestCase(); - tc.setName(name); - tc.setProjectId(projectId); - tc.setParentId(parentId); - - final Response res = testApi.create(projectId.intValue(), objectMapper.writeValueAsString(tc), jwt); - assertEquals(HttpStatus.CREATED.value(), res.getStatus()); - return res.readEntity(TestCase.class); - } - - private TestCase createTestCaseWithSteps(Long projectId, String name, Long parentId, String jwt) throws Exception { - final TestCase tc = new TestCase(); - tc.setName(name); - tc.setProjectId(projectId); - tc.setParentId(parentId); - - final ParameterizedSymbol resetSymbol = symbolUtils.createResetSymbol(project, jwt); - final ParameterizedSymbol authSymbol = symbolUtils.createAuthSymbol(project, ADMIN_EMAIL, ADMIN_PASSWORD, jwt); - final ParameterizedSymbol getProfileSymbol = symbolUtils.createGetProfileSymbol(project, jwt); - - final var preStep = new TestCaseStep(); - preStep.setPSymbol(resetSymbol); - tc.getPreSteps().add(preStep); - - final var step1 = new TestCaseStep(); - step1.setPSymbol(authSymbol); - tc.getSteps().add(step1); - - final var step2 = new TestCaseStep(); - step2.setPSymbol(getProfileSymbol); - tc.getSteps().add(step2); - - final Response res = testApi.create(projectId.intValue(), objectMapper.writeValueAsString(tc), jwt); - assertEquals(HttpStatus.CREATED.value(), res.getStatus()); - return res.readEntity(TestCase.class); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static abstract class IgnoreTestReportFieldsMixin { - @JsonIgnore - abstract void setTime(Long time); - - @JsonIgnore - abstract void setNumTests(Long num); - - @JsonIgnore - abstract void setNumTestsFailed(Long num); - - @JsonIgnore - abstract void setNumTestsPassed(Long num); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static abstract class IgnoreTestExecutionResultFieldsMixin { - @JsonIgnore - abstract void setOutput(String output); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static abstract class IgnoreTestCaseResultFieldsMixin { - @JsonIgnore - abstract void setPassed(boolean passed); - - @JsonIgnore - abstract void setFailureMessage(String failureMessage); - - @JsonIgnore - abstract de.learnlib.alex.testing.entities.Test.TestRepresentation getTestRepresentation(); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static abstract class IgnoreTestSuiteResultFieldsMixin { - @JsonIgnore - abstract void setPassed(boolean passed); - - @JsonIgnore - abstract void setFailureMessage(String failureMessage); - - @JsonIgnore - abstract de.learnlib.alex.testing.entities.Test.TestRepresentation getTestRepresentation(); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/AbstractResourceIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/AbstractResourceIT.java deleted file mode 100644 index 424834879..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/AbstractResourceIT.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.jayway.jsonpath.JsonPath; -import de.learnlib.alex.auth.dao.UserDAO; -import de.learnlib.alex.auth.repositories.UserRepository; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.integrationtests.TestPostgresqlContainer; -import de.learnlib.alex.settings.dao.SettingsDAO; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.transaction.annotation.Transactional; -import org.testcontainers.containers.PostgreSQLContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; - -@Testcontainers -@ExtendWith(SpringExtension.class) -@SpringBootTest( - webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT -) -public abstract class AbstractResourceIT { - - @Container - public static PostgreSQLContainer postgreSQLContainer = TestPostgresqlContainer.getInstance(); - - protected static final String ADMIN_EMAIL = "admin@alex.example"; - - protected static final String ADMIN_PASSWORD = "admin"; - - @LocalServerPort - protected int port; - - protected Client client = ClientBuilder.newClient(); - - @Autowired - protected ObjectMapper objectMapper; - - @Autowired - protected UserDAO userDAO; - - @Autowired - protected ProjectDAO projectDAO; - - @Autowired - protected SettingsDAO settingsDAO; - - @Autowired - private UserRepository userRepository; - - protected String baseUrl() { - return "http://localhost/" + port + "/rest"; - } - - @BeforeEach - public void pre() throws Exception { - } - - @AfterEach - @Transactional - public void post() throws Exception { - final var admin = userDAO.getByID(1L); - - // delete all users except the admin - for (var user : userRepository.findAll()) { - if (!user.equals(admin)) { - userDAO.delete(admin, user.getId()); - } - } - - // delete projects of admin - for (var project : projectDAO.getAll(admin)) { - projectDAO.delete(admin, project.getId()); - } - - final var settings = settingsDAO.get(); - settings.setAllowUserRegistration(true); - settingsDAO.update(settings); - } - - protected void checkIsRestError(String body) { - JsonPath.read(body, "statusCode"); - JsonPath.read(body, "statusText"); - JsonPath.read(body, "message"); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/CounterResourceIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/CounterResourceIT.java deleted file mode 100644 index 87f6a492a..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/CounterResourceIT.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import de.learnlib.alex.data.entities.Counter; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.integrationtests.SpringRestError; -import de.learnlib.alex.integrationtests.resources.api.CounterApi; -import de.learnlib.alex.integrationtests.resources.api.ProjectApi; -import de.learnlib.alex.integrationtests.resources.api.UserApi; -import java.util.Arrays; -import java.util.List; -import javax.ws.rs.NotFoundException; -import javax.ws.rs.core.GenericType; -import javax.ws.rs.core.Response; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.http.HttpStatus; - -public class CounterResourceIT extends AbstractResourceIT { - - private String jwtUser1; - private String jwtUser2; - - private Project project1; - private Project project2; - - private UserApi userApi; - private ProjectApi projectApi; - private CounterApi counterApi; - - @BeforeEach - public void pre() { - userApi = new UserApi(client, port); - projectApi = new ProjectApi(client, port); - counterApi = new CounterApi(client, port); - - userApi.create("{\"email\":\"test1@test.de\",\"username\":\"test1\",\"password\":\"test\"}"); - userApi.create("{\"email\":\"test2@test.de\",\"username\":\"test2\",\"password\":\"test\"}"); - - jwtUser1 = userApi.login("test1@test.de", "test"); - jwtUser2 = userApi.login("test2@test.de", "test"); - - project1 = projectApi.create("{\"name\":\"test\",\"url\":\"http://localhost:8080/"}", jwtUser1) - .readEntity(Project.class); - - project2 = projectApi.create("{\"name\":\"test\",\"url\":\"http://localhost:8080/"}", jwtUser2) - .readEntity(Project.class); - } - - @Test - public void shouldCreateACounter() { - final Counter counter = createCounter("counter", project1, 1); - final Response res1 = counterApi.create(project1.getId(), counter, jwtUser1); - - assertEquals(HttpStatus.CREATED.value(), res1.getStatus()); - final Counter createdCounter = res1.readEntity(Counter.class); - - assertCounter(createdCounter, "counter", 1); - assertEquals(1, getNumberOfCounters(project1.getId(), jwtUser1)); - } - - @Test - public void shouldNotCreateTheSameCounterTwice() { - final Counter counter1 = createCounter("counter", project1, 1); - counterApi.create(project1.getId(), counter1, jwtUser1); - - final Counter counter2 = createCounter("counter", project1, 1); - final Response res1 = counterApi.create(project1.getId(), counter2, jwtUser1); - - assertEquals(HttpStatus.BAD_REQUEST.value(), res1.getStatus()); - assertEquals(1, getNumberOfCounters(project1.getId(), jwtUser1)); - } - - @Test - public void shouldNotCreateCounterIfProjectCannotBeFound() { - final Counter counter = createCounter("counter", new Project(-1L), 1); - final Response res1 = counterApi.create(-1L, counter, jwtUser1); - - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), res1.getStatus()); - assertEquals(0, getNumberOfCounters(project1.getId(), jwtUser1)); - } - - @Test - public void shouldNotCreateACounterInAnotherUsersProject() { - final Counter counter = createCounter("counter1", project2, 1); - final Response res1 = counterApi.create(project2.getId(), counter, jwtUser1); - - assertEquals(HttpStatus.UNAUTHORIZED.value(), res1.getStatus()); - - final Response res2 = counterApi.getAll(project1.getId(), jwtUser1); - assertEquals(0, res2.readEntity(new GenericType>() { - }).size()); - - final Response res3 = counterApi.getAll(project2.getId(), jwtUser2); - assertEquals(0, res3.readEntity(new GenericType>() { - }).size()); - } - - @Test - public void shouldGetAllCounters() { - final Counter counter1 = createCounter("counter1", project1, 1); - final Counter counter2 = createCounter("counter2", project1, 1); - final Counter counter3 = createCounter("counter3", project1, 1); - - counterApi.create(project1.getId(), counter1, jwtUser1); - counterApi.create(project1.getId(), counter2, jwtUser1); - counterApi.create(project1.getId(), counter3, jwtUser1); - - final Response res = counterApi.getAll(project1.getId(), jwtUser1); - - assertEquals(HttpStatus.OK.value(), res.getStatus()); - assertEquals(3, getNumberOfCounters(project1.getId(), jwtUser1)); - } - - @Test - public void shouldNotGetCountersOfAnotherUsersProject() { - final Counter counter = createCounter("counter", project1, 1); - counterApi.create(project2.getId(), counter, jwtUser2); - - final Response res = counterApi.getAll(project2.getId(), jwtUser1); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res.getStatus()); - res.readEntity(SpringRestError.class); - } - - @Test - public void shouldUpdateValueOfACounter() { - Counter counter = createCounter("counter1", project1, 1); - counter = counterApi.create(project1.getId(), counter, jwtUser1).readEntity(Counter.class); - - counter.setValue(5); - - final Response res1 = counterApi.update(project1.getId(), counter.getId(), counter, jwtUser1); - assertEquals(HttpStatus.OK.value(), res1.getStatus()); - - final Counter updatedCounter = res1.readEntity(Counter.class); - assertCounter(updatedCounter, "counter1", 5); - } - - @Test - public void shouldNotUpdateNameOfACounter() { - Counter counter = createCounter("counter1", project1, 1); - counter = counterApi.create(project1.getId(), counter, jwtUser1).readEntity(Counter.class); - - counter.setName("updatedName"); - - final Response res1 = counterApi.update(project1.getId(), counter.getId(), counter, jwtUser1); - assertEquals(HttpStatus.OK.value(), res1.getStatus()); - - counter = getCounterById(project1.getId(), counter.getId(), jwtUser1); - assertCounter(counter, "counter1", 1); - } - - @Test - public void shouldNotUpdateAnotherUsersCounter() { - Counter counter = createCounter("counter1", project1, 1); - counter = counterApi.create(project1.getId(), counter, jwtUser1).readEntity(Counter.class); - - counter.setValue(5); - - final Response res1 = counterApi.update(project1.getId(), counter.getId(), counter, jwtUser2); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res1.getStatus()); - res1.readEntity(SpringRestError.class); - - counter = getCounterById(project1.getId(), counter.getId(), jwtUser1); - assertCounter(counter, "counter1", 1); - } - - @Test - public void shouldDeleteCounter() { - Counter counter1 = createCounter("counter1", project1, 1); - counter1 = counterApi.create(project1.getId(), counter1, jwtUser1).readEntity(Counter.class); - - Counter counter2 = createCounter("counter2", project1, 1); - counter2 = counterApi.create(project1.getId(), counter2, jwtUser1).readEntity(Counter.class); - - final Response res = counterApi.delete(project1.getId(), counter1, jwtUser1); - assertEquals(HttpStatus.NO_CONTENT.value(), res.getStatus()); - assertEquals("", res.readEntity(String.class)); - assertEquals(1, getNumberOfCounters(project1.getId(), jwtUser1)); - } - - @Test - public void shouldNotDeleteAnotherUsersCounter() { - Counter counter = createCounter("counter1", project2, 1); - counter = counterApi.create(project2.getId(), counter, jwtUser2).readEntity(Counter.class); - - final Response res = counterApi.delete(project2.getId(), counter, jwtUser1); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res.getStatus()); - res.readEntity(SpringRestError.class); - assertEquals(1, getNumberOfCounters(project2.getId(), jwtUser2)); - } - - @Test - public void shouldFailToDeleteCounterIfItDoesNotExist() { - final Counter counter = new Counter(); - counter.setProject(project1); - counter.setName("counter"); - counter.setId(-1L); - - final Response res = counterApi.delete(project1.getId(), counter, jwtUser1); - assertEquals(HttpStatus.NOT_FOUND.value(), res.getStatus()); - res.readEntity(SpringRestError.class); - assertEquals(0, getNumberOfCounters(project1.getId(), jwtUser1)); - } - - @Test - public void shouldDeleteMultipleCountersAtOnce() { - Counter counter1 = createCounter("counter1", project1, 1); - counter1 = counterApi.create(project1.getId(), counter1, jwtUser1).readEntity(Counter.class); - - Counter counter2 = createCounter("counter2", project1, 1); - counter2 = counterApi.create(project1.getId(), counter2, jwtUser1).readEntity(Counter.class); - - final Response res = counterApi.delete(project1.getId(), Arrays.asList(counter1, counter2), jwtUser1); - assertEquals(HttpStatus.NO_CONTENT.value(), res.getStatus()); - assertEquals("", res.readEntity(String.class)); - assertEquals(0, getNumberOfCounters(project1.getId(), jwtUser1)); - } - - @Test - public void shouldNotDeleteMultipleCountersIfOneDoesNotExist() { - Counter counter1 = createCounter("counter1", project1, 1); - counter1 = counterApi.create(project1.getId(), counter1, jwtUser1).readEntity(Counter.class); - - Counter counter2 = createCounter("counter2", project1, 1); - counter2 = counterApi.create(project1.getId(), counter2, jwtUser1).readEntity(Counter.class); - - final Counter counter3 = createCounter("counter3", project1, 1); - counter3.setId(-1L); - - final Response res = counterApi.delete(project1.getId(), Arrays.asList(counter1, counter2, counter3), jwtUser1); - assertEquals(HttpStatus.NOT_FOUND.value(), res.getStatus()); - res.readEntity(SpringRestError.class); - assertEquals(2, getNumberOfCounters(project1.getId(), jwtUser1)); - } - - private int getNumberOfCounters(Long projectId, String jwt) { - return counterApi.getAll(projectId, jwt) - .readEntity(new GenericType>() { - }) - .size(); - } - - private Counter getCounterById(Long projectId, Long counterId, String jwt) { - return counterApi.getAll(projectId, jwt) - .readEntity(new GenericType>() { - }) - .stream() - .filter(c -> c.getId().equals(counterId)) - .findFirst() - .orElseThrow(NotFoundException::new); - } - - private Counter createCounter(String name, Project project, Integer value) { - final Counter counter = new Counter(); - counter.setName(name); - counter.setProject(project); - counter.setValue(value); - return counter; - } - - private void assertCounter(Counter counter, String name, Integer value) { - assertEquals(name, counter.getName()); - assertEquals(value, counter.getValue()); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/LearnerResourceIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/LearnerResourceIT.java deleted file mode 100644 index 17a29d040..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/LearnerResourceIT.java +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources; - -import static org.awaitility.Awaitility.await; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.jayway.jsonpath.JsonPath; -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.integrationtests.SpringRestError; -import de.learnlib.alex.integrationtests.resources.api.LearnerApi; -import de.learnlib.alex.integrationtests.resources.api.LearnerResultApi; -import de.learnlib.alex.integrationtests.resources.api.ProjectApi; -import de.learnlib.alex.integrationtests.resources.api.SymbolApi; -import de.learnlib.alex.integrationtests.resources.api.UserApi; -import de.learnlib.alex.integrationtests.resources.utils.SymbolUtils; -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.learning.entities.LearnerResultStep; -import de.learnlib.alex.learning.entities.LearnerResumeConfiguration; -import de.learnlib.alex.learning.entities.LearnerSetup; -import de.learnlib.alex.learning.entities.LearnerStartConfiguration; -import de.learnlib.alex.learning.entities.LearnerStatus; -import de.learnlib.alex.learning.entities.WebDriverConfig; -import de.learnlib.alex.learning.entities.algorithms.TTT; -import de.learnlib.alex.learning.entities.learnlibproxies.eqproxies.MealyRandomWordsEQOracleProxy; -import de.learnlib.alex.learning.entities.learnlibproxies.eqproxies.SampleEQOracleProxy; -import java.io.IOException; -import java.net.InetAddress; -import java.time.Duration; -import java.util.Arrays; -import java.util.Collections; -import java.util.concurrent.TimeUnit; -import javax.ws.rs.core.Response; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.http.HttpStatus; - -public class LearnerResourceIT extends AbstractResourceIT { - - private String jwt; - private Project project; - private LearnerStartConfiguration startConfiguration; - private LearnerApi learnerApi; - private LearnerResultApi learnerResultApi; - private String memberJwt; - - @BeforeEach - public void pre() throws Exception { - objectMapper.addMixIn(LearnerResult.class, LearnerSetupResourceIT.IgnoreLearnerResultFieldsMixin.class); - objectMapper.addMixIn(LearnerResultStep.class, LearnerSetupResourceIT.IgnoreLearnerResultStepFieldsMixin.class); - objectMapper.addMixIn(LearnerStatus.class, LearnerSetupResourceIT.IgnoreLearnerResultStepFieldsMixin.class); - objectMapper.addMixIn(ExecuteResult.class, LearnerSetupResourceIT.IgnoreLearnerResultStepFieldsMixin.class); - - final UserApi userApi = new UserApi(client, port); - final ProjectApi projectApi = new ProjectApi(client, port); - final SymbolApi symbolApi = new SymbolApi(client, port); - final SymbolUtils symbolUtils = new SymbolUtils(symbolApi); - - learnerApi = new LearnerApi(client, port); - learnerResultApi = new LearnerResultApi(client, port); - - jwt = userApi.login(ADMIN_EMAIL, ADMIN_PASSWORD); - - final Response res1 = userApi.create("{\"email\":\"test1@test.de\", \"username\":\"test1\", \"password\":\"test\"}"); - final int memberId = JsonPath.read(res1.readEntity(String.class), "id"); - memberJwt = userApi.login("test1@test.de", "test"); - - final String url = "http://" + InetAddress.getLocalHost().getHostAddress() + ":" + port; - project = projectApi.create("{\"name\":\"test\",\"url\":\"" + url + "\"}", jwt) - .readEntity(Project.class); - - projectApi.addMembers(project.getId(), Collections.singletonList((long) memberId), jwt); - - final ParameterizedSymbol resetSymbol = symbolUtils.createResetSymbol(project, jwt); - final ParameterizedSymbol authSymbol = symbolUtils.createAuthSymbol(project, ADMIN_EMAIL, ADMIN_PASSWORD, jwt); - final ParameterizedSymbol getProfileSymbol = symbolUtils.createGetProfileSymbol(project, jwt); - - final MealyRandomWordsEQOracleProxy eqOracleProxy = new MealyRandomWordsEQOracleProxy(); - eqOracleProxy.setBatchSize(1); - eqOracleProxy.setMinLength(3); - eqOracleProxy.setMaxLength(3); - eqOracleProxy.setMaxNoOfTests(3); - - final LearnerSetup learnerSetup = new LearnerSetup(); - learnerSetup.setProject(project); - learnerSetup.setPreSymbol(resetSymbol); - learnerSetup.setSymbols(Arrays.asList(authSymbol, getProfileSymbol)); - - final var webDriverConfig = new WebDriverConfig(); - webDriverConfig.setBrowser("chrome"); - learnerSetup.setWebDriver(webDriverConfig); - learnerSetup.setEquivalenceOracle(eqOracleProxy); - learnerSetup.setAlgorithm(new TTT()); - learnerSetup.setEnvironments(project.getEnvironments()); - - startConfiguration = new LearnerStartConfiguration(); - startConfiguration.setSetup(learnerSetup); - } - - @Test - public void shouldStartLearningProcess() throws Exception { - final Response res1 = learnerApi.start(project.getId(), startConfiguration, jwt); - assertEquals(HttpStatus.OK.value(), res1.getStatus()); - - LearnerResult result = objectMapper.readValue(res1.readEntity(String.class), LearnerResult.class); - assertTrue(isLearnerProcessActive(result)); - - result = learn(result.getTestNo()); - assertLearnerResult(result, LearnerResult.Status.FINISHED, 2, 2); - } - - @Test - public void shouldResumeLearningProcess() throws Exception { - startConfiguration.getSetup().setEquivalenceOracle(new SampleEQOracleProxy()); - - final Response res1 = learnerApi.start(project.getId(), startConfiguration, jwt); - var result = objectMapper.readValue(res1.readEntity(String.class), LearnerResult.class); - result = learn(result.getTestNo()); - - assertLearnerResult(result, LearnerResult.Status.FINISHED, 1, 1); - - // resume - final MealyRandomWordsEQOracleProxy eqOracleProxy = new MealyRandomWordsEQOracleProxy(); - eqOracleProxy.setBatchSize(1); - eqOracleProxy.setMinLength(3); - eqOracleProxy.setMaxLength(3); - eqOracleProxy.setMaxNoOfTests(3); - - final LearnerResumeConfiguration resumeConfiguration = new LearnerResumeConfiguration(); - resumeConfiguration.setStepNo(result.getSteps().get(0).getStepNo().intValue()); - resumeConfiguration.setEqOracle(eqOracleProxy); - - final Response res2 = learnerApi.resume(project.getId(), result.getTestNo(), resumeConfiguration, jwt); - assertEquals(HttpStatus.OK.value(), res2.getStatus()); - - result = learn(result.getTestNo()); - assertLearnerResult(result, LearnerResult.Status.FINISHED, 2, 2); - } - - @Test - public void shouldAbortLearningProcessOfMemberAsOwner() throws IOException { - abortLearningProcess(memberJwt, jwt); - } - - @Test - public void shouldAbortOwnLearningProcessAsOwner() throws IOException { - abortLearningProcess(jwt, jwt); - } - - @Test - public void shouldAbortOwnLearningProcessAsMember() throws IOException { - abortLearningProcess(memberJwt, memberJwt); - } - - @Test - public void shouldFailToAbortLearningProcessOfOwnerAsMember() throws Exception { - final Response res1 = learnerApi.start(project.getId(), startConfiguration, jwt); - assertEquals(HttpStatus.OK.value(), res1.getStatus()); - - final LearnerResult result = objectMapper.readValue(res1.readEntity(String.class), LearnerResult.class); - - final Response res2 = learnerApi.abort(project.getId(), result.getId(), memberJwt); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res2.getStatus()); - - learn(result.getTestNo()); - } - - @Test - public void shouldFailToResumeWithInvalidStepToContinueFrom() throws Exception { - startConfiguration.getSetup().setEquivalenceOracle(new SampleEQOracleProxy()); - - final Response res1 = learnerApi.start(project.getId(), startConfiguration, jwt); - assertEquals(HttpStatus.OK.value(), res1.getStatus()); - final LearnerResult result = objectMapper.readValue(res1.readEntity(String.class), LearnerResult.class); - - learn(result.getTestNo()); - - final LearnerResumeConfiguration resumeConfiguration = new LearnerResumeConfiguration(); - resumeConfiguration.setStepNo(5); // does not exist - resumeConfiguration.setEqOracle(new SampleEQOracleProxy()); - - final Response res2 = learnerApi.resume(project.getId(), result.getTestNo(), resumeConfiguration, jwt); - assertEquals(HttpStatus.BAD_REQUEST.value(), res2.getStatus()); - res2.readEntity(SpringRestError.class); - - final Response res3 = learnerApi.getStatus(project.getId(), jwt); - final LearnerStatus status = objectMapper.readValue(res3.readEntity(String.class), LearnerStatus.class); - assertEquals(0, status.getQueue().size()); - } - - @Test - public void shouldResumeLearningProcessWithSymbolsToAdd() throws Exception { - startConfiguration.getSetup().setEquivalenceOracle(new SampleEQOracleProxy()); - - final ParameterizedSymbol symbolToLearn = startConfiguration.getSetup().getSymbols().get(0); - final ParameterizedSymbol symbolToAdd = startConfiguration.getSetup().getSymbols().get(1); - startConfiguration.getSetup().setSymbols(Collections.singletonList(symbolToLearn)); - - final Response res1 = learnerApi.start(project.getId(), startConfiguration, jwt); - LearnerResult result = objectMapper.readValue(res1.readEntity(String.class), LearnerResult.class); - result = learn(result.getTestNo()); - - assertLearnerResult(result, LearnerResult.Status.FINISHED, 1, 1); - - final MealyRandomWordsEQOracleProxy eqOracleProxy = new MealyRandomWordsEQOracleProxy(); - eqOracleProxy.setBatchSize(1); - eqOracleProxy.setMinLength(3); - eqOracleProxy.setMaxLength(3); - eqOracleProxy.setMaxNoOfTests(3); - - final LearnerResumeConfiguration resumeConfiguration = new LearnerResumeConfiguration(); - resumeConfiguration.setStepNo(result.getSteps().get(0).getStepNo().intValue()); - resumeConfiguration.setEqOracle(eqOracleProxy); - resumeConfiguration.getSymbolsToAdd().add(symbolToAdd); - - final Response res2 = learnerApi.resume(project.getId(), result.getTestNo(), resumeConfiguration, jwt); - assertEquals(HttpStatus.OK.value(), res2.getStatus()); - result = learn(result.getTestNo()); - - assertLearnerResult(result, LearnerResult.Status.FINISHED, 3, 2); - assertEquals(2, result.getSetup().getSymbols().size()); - } - - @Test - public void shouldGetEmptyStatusIfNoLearningProcessIsActive() throws Exception { - final Response res = learnerApi.getStatus(project.getId(), jwt); - assertEquals(HttpStatus.OK.value(), res.getStatus()); - - final var status = objectMapper.readValue(res.readEntity(String.class), LearnerStatus.class); - assertEquals(0, status.getQueue().size()); - assertNull(status.getCurrentProcess()); - } - - private void assertLearnerResult(LearnerResult result, LearnerResult.Status status, int numSteps, int numStates) { - assertEquals(status, result.getStatus()); - assertFalse(result.isError()); - assertEquals(numSteps, result.getSteps().size()); - assertEquals(numStates, result.getSteps().get(numSteps - 1).getHypothesis().getNodes().size()); - } - - private LearnerResult learn(Long testNo) throws Exception { - await().atMost(10, TimeUnit.SECONDS) - .pollInSameThread() - .pollDelay(Duration.ofSeconds(1)) - .pollInterval(Duration.ofSeconds(1)) - .until(() -> { - final var result = getLearnerResult(project.getId(), testNo, jwt); - return !isLearnerProcessActive(result); - }); - - return getLearnerResult(project.getId(), testNo, jwt); - } - - private boolean isLearnerProcessActive(LearnerResult result) { - return result.getStatus().equals(LearnerResult.Status.PENDING) - || result.getStatus().equals(LearnerResult.Status.IN_PROGRESS); - } - - private boolean isLearnerProcessAbortedFinishedOrFailed(LearnerResult result) { - return result.getStatus().equals(LearnerResult.Status.ABORTED) - || result.getStatus().equals(LearnerResult.Status.FINISHED) - || result.getStatus().equals(LearnerResult.Status.FAILED); - } - - private LearnerResult getLearnerResult(Long projectId, Long testNo, String jwt) throws JsonProcessingException { - final var res = learnerResultApi.get(projectId, testNo, jwt); - return objectMapper.readValue(res.readEntity(String.class), LearnerResult.class); - } - - private void abortLearningProcess(String jwtInitiator, String jwtAborter) throws IOException { - final var res1 = learnerApi.start(project.getId(), startConfiguration, jwtInitiator); - assertEquals(HttpStatus.OK.value(), res1.getStatus()); - - var result = objectMapper.readValue(res1.readEntity(String.class), LearnerResult.class); - assertTrue(isLearnerProcessActive(result)); - - final var res2 = learnerApi.abort(project.getId(), result.getId(), jwtAborter); - assertEquals(HttpStatus.OK.value(), res2.getStatus()); - - // eventually the result will be aborted or finished - final var finalResult = result; - await().atMost(10, TimeUnit.SECONDS).until(() -> { - final var r = getLearnerResult(project.getId(), finalResult.getTestNo(), jwtInitiator); - return isLearnerProcessAbortedFinishedOrFailed(r); - }); - - result = getLearnerResult(project.getId(), finalResult.getTestNo(), jwtInitiator); - assertTrue(isLearnerProcessAbortedFinishedOrFailed(result)); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/LearnerSetupResourceIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/LearnerSetupResourceIT.java deleted file mode 100644 index b96842a3e..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/LearnerSetupResourceIT.java +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources; - -import static org.awaitility.Awaitility.await; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.core.JsonProcessingException; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolActionStep; -import de.learnlib.alex.data.entities.actions.misc.SetVariableAction; -import de.learnlib.alex.integrationtests.SpringRestError; -import de.learnlib.alex.integrationtests.resources.api.LearnerResultApi; -import de.learnlib.alex.integrationtests.resources.api.LearnerSetupApi; -import de.learnlib.alex.integrationtests.resources.api.LtsFormulaSuiteApi; -import de.learnlib.alex.integrationtests.resources.api.ProjectApi; -import de.learnlib.alex.integrationtests.resources.api.SymbolApi; -import de.learnlib.alex.integrationtests.resources.api.UserApi; -import de.learnlib.alex.learning.entities.LearnerOptions; -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.learning.entities.LearnerResultStep; -import de.learnlib.alex.learning.entities.LearnerSetup; -import de.learnlib.alex.learning.entities.Statistics; -import de.learnlib.alex.learning.entities.WebDriverConfig; -import de.learnlib.alex.learning.entities.algorithms.TTT; -import de.learnlib.alex.learning.entities.learnlibproxies.eqproxies.MealyRandomWordsEQOracleProxy; -import de.learnlib.alex.modelchecking.entities.LtsFormulaSuite; -import java.io.IOException; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import javax.ws.rs.core.GenericType; -import javax.ws.rs.core.Response; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.http.HttpStatus; - -public class LearnerSetupResourceIT extends AbstractResourceIT { - - private LearnerSetupApi learnerSetupApi; - private LearnerResultApi learnerResultApi; - private LtsFormulaSuiteApi ltsFormulaSuiteApi; - - private Project project; - private List symbols; - private String jwt; - - @BeforeEach - public void pre() throws Exception { - final UserApi userApi = new UserApi(client, port); - final ProjectApi projectApi = new ProjectApi(client, port); - final SymbolApi symbolApi = new SymbolApi(client, port); - - learnerSetupApi = new LearnerSetupApi(client, port); - learnerResultApi = new LearnerResultApi(client, port); - ltsFormulaSuiteApi = new LtsFormulaSuiteApi(client, port); - - jwt = userApi.login("admin@alex.example", "admin"); - project = projectApi.create("{\"name\":\"test\",\"url\":\"http://" + InetAddress.getLocalHost().getHostName() + " :" + port + "\"}", jwt) - .readEntity(Project.class); - - final SetVariableAction action1 = new SetVariableAction(); - action1.setName("v1"); - action1.setValue("val1"); - - final SymbolActionStep step1 = new SymbolActionStep(); - step1.setAction(action1); - - final SetVariableAction action2 = new SetVariableAction(); - action2.setName("v2"); - action2.setValue("val2"); - - final SymbolActionStep step2 = new SymbolActionStep(); - step2.setAction(action2); - - final Symbol s1 = new Symbol(); - s1.setProject(project); - s1.setName("s1"); - s1.getSteps().add(step1); - - final Symbol s2 = new Symbol(); - s2.setProject(project); - s2.setName("s2"); - s2.getSteps().add(step2); - - symbols = new ArrayList<>(); - symbols.add(symbolApi.create(project.getId().intValue(), objectMapper.writeValueAsString(s1), jwt) - .readEntity(Symbol.class)); - symbols.add(symbolApi.create(project.getId().intValue(), objectMapper.writeValueAsString(s2), jwt) - .readEntity(Symbol.class)); - } - - @Test - public void startLearningProcessFromSetupWithoutOptions() throws IOException { - startLearningFromSetup(null, "testSetup"); - } - - @Test - public void startLearningProcessFromSetupWithOptions() throws IOException { - final String comment = "testComment"; - final LearnerOptions options = new LearnerOptions(); - options.setComment(comment); - startLearningFromSetup(options, comment); - } - - private void startLearningFromSetup(LearnerOptions options, String expectedComment) throws IOException { - objectMapper.addMixIn(LearnerResult.class, IgnoreLearnerResultFieldsMixin.class); - objectMapper.addMixIn(LearnerResultStep.class, IgnoreLearnerResultStepFieldsMixin.class); - - final LearnerSetup setup = learnerSetupApi.create(project.getId(), createDefaultLearnerSetup(), jwt) - .readEntity(LearnerSetup.class); - - final Response res; - if (options == null) { - res = learnerSetupApi.run(project.getId(), setup.getId(), jwt); - } else { - res = learnerSetupApi.run(project.getId(), setup.getId(), options, jwt); - } - assertEquals(HttpStatus.OK.value(), res.getStatus()); - - LearnerResult result = objectMapper.readValue(res.readEntity(String.class), LearnerResult.class); - assertTrue(result.getStatus().equals(LearnerResult.Status.IN_PROGRESS) - || result.getStatus().equals(LearnerResult.Status.PENDING)); - - LearnerResult finalResult = result; - await().atMost(10, TimeUnit.SECONDS).until(() -> { - final var r = getLearnerResult(project.getId(), finalResult.getTestNo(), jwt); - return r.getStatus().equals(LearnerResult.Status.FINISHED) - || r.getStatus().equals(LearnerResult.Status.ABORTED); - }); - - result = getLearnerResult(project.getId(), result.getTestNo(), jwt); - - assertEquals(LearnerResult.Status.FINISHED, result.getStatus()); - assertEquals(expectedComment, result.getComment()); - assertEquals(1, result.getSteps().size()); - assertEquals(1, result.getSteps().get(0).getHypothesis().getNodes().size()); - assertNotEquals(setup.getId(), result.getSetup().getId()); - assertFalse(result.isError()); - } - - private LearnerResult getLearnerResult(Long projectId, Long testNo, String jwt) throws JsonProcessingException { - final Response res = learnerResultApi.get(projectId, testNo, jwt); - return objectMapper.readValue(res.readEntity(String.class), LearnerResult.class); - } - - @Test - public void shouldNotCreateLearnerSetupWithoutPreSymbol() { - LearnerSetup ls = createDefaultLearnerSetup(); - ls.setPreSymbol(null); - - final Response res = learnerSetupApi.create(project.getId(), ls, jwt); - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - assertEquals(0, getAllSetups().size()); - res.readEntity(SpringRestError.class); - } - - @Test - public void shouldNotCreateLearnerSetupWithoutAlphabet() { - LearnerSetup ls = createDefaultLearnerSetup(); - ls.setSymbols(new ArrayList<>()); - - final Response res = learnerSetupApi.create(project.getId(), ls, jwt); - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - assertEquals(0, getAllSetups().size()); - res.readEntity(SpringRestError.class); - } - - @Test - public void shouldCreateLearnerSetup() { - final LearnerSetup ls = createDefaultLearnerSetup(); - final Response res = learnerSetupApi.create(project.getId(), ls, jwt); - final LearnerSetup createdSetup = res.readEntity(LearnerSetup.class); - - assertEquals(HttpStatus.CREATED.value(), res.getStatus()); - assertEquals(1, getAllSetups().size()); - assertNotNull(createdSetup.getModelCheckingConfig()); - compareTo(ls, createdSetup); - } - - @Test - public void shouldNotCreateLearnerSetupWithDuplicateSymbolAliases() { - final var ls = createDefaultLearnerSetup(); - ls.getSymbols().forEach(ps -> ps.setAlias("test")); - - final var res = learnerSetupApi.create(project.getId(), ls, jwt); - - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - res.readEntity(SpringRestError.class); - } - - @Test - public void shouldNotCreateLearnerSetupWithDuplicateSymbols() { - final var ls = createDefaultLearnerSetup(); - ls.setSymbols(Arrays.asList( - ls.getSymbols().get(0), - ls.getSymbols().get(0) - )); - - final var res = learnerSetupApi.create(project.getId(), ls, jwt); - - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - res.readEntity(SpringRestError.class); - } - - @Test - public void shouldCreateLearnerSetupWithModelCheckingConfig() { - final var fs1 = createFormulaSuite(project.getId(), "suite1", jwt); - final var fs2 = createFormulaSuite(project.getId(), "suite2", jwt); - - final var ls = createDefaultLearnerSetup(); - ls.getModelCheckingConfig().getFormulaSuites().add(fs1); - ls.getModelCheckingConfig().getFormulaSuites().add(fs2); - - final var res = learnerSetupApi.create(project.getId(), ls, jwt); - assertEquals(HttpStatus.CREATED.value(), res.getStatus()); - - final var createdSetup = res.readEntity(LearnerSetup.class); - final var config = createdSetup.getModelCheckingConfig(); - assertNotNull(config); - assertEquals(2, config.getFormulaSuites().size()); - assertTrue(config.getFormulaSuites().stream().anyMatch(fs -> fs.getName().equals("suite1"))); - assertTrue(config.getFormulaSuites().stream().anyMatch(fs -> fs.getName().equals("suite2"))); - } - - @Test - public void shouldUpdateModelCheckingConfigOfLearnerSetup() { - final var fs1 = createFormulaSuite(project.getId(), "suite1", jwt); - final var fs2 = createFormulaSuite(project.getId(), "suite2", jwt); - - final var ls = createDefaultLearnerSetup(); - ls.getModelCheckingConfig().getFormulaSuites().add(fs1); - ls.getModelCheckingConfig().getFormulaSuites().add(fs2); - - final var res = learnerSetupApi.create(project.getId(), ls, jwt); - final var createdSetup = res.readEntity(LearnerSetup.class); - final var config = createdSetup.getModelCheckingConfig(); - - // change properties and remove a suite - config.setMinUnfolds(5); - config.setMultiplier(0.5); - config.getFormulaSuites().removeIf(fs -> fs.getName().equals("suite1")); - - // update - final var res2 = learnerSetupApi.update(project.getId(), createdSetup.getId(), createdSetup, jwt); - assertEquals(HttpStatus.OK.value(), res2.getStatus()); - - final var updatedSetup = res2.readEntity(LearnerSetup.class); - final var updatedConfig = updatedSetup.getModelCheckingConfig(); - - // verify updated properties - assertNotNull(updatedConfig); - assertEquals(5, (long) updatedConfig.getMinUnfolds()); - assertEquals(0.5, updatedConfig.getMultiplier(), 0.0); - assertEquals(1, updatedConfig.getFormulaSuites().size()); - assertTrue(updatedConfig.getFormulaSuites().stream().noneMatch(fs -> fs.getName().equals("suite1"))); - } - - private LtsFormulaSuite createFormulaSuite(Long projectId, String name, String jwt) { - final var fs = new LtsFormulaSuite(); - fs.setName(name); - - final var res = ltsFormulaSuiteApi.create(projectId, fs, jwt); - assertEquals(HttpStatus.CREATED.value(), res.getStatus()); - - return res.readEntity(LtsFormulaSuite.class); - } - - @Test - public void shouldFailToCreateLearnerSetupWithoutModelCheckingConfig() { - final LearnerSetup ls = createDefaultLearnerSetup(); - ls.setModelCheckingConfig(null); - - final Response res = learnerSetupApi.create(project.getId(), ls, jwt); - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - res.readEntity(SpringRestError.class); - - assertEquals(0, getAllSetups().size()); - } - - @Test - public void shouldDeleteLearnerSetup() { - final LearnerSetup ls = learnerSetupApi.create(project.getId(), createDefaultLearnerSetup(), jwt) - .readEntity(LearnerSetup.class); - - final Response res = learnerSetupApi.delete(project.getId(), ls.getId(), jwt); - assertEquals(HttpStatus.NO_CONTENT.value(), res.getStatus()); - assertEquals("", res.readEntity(String.class)); - assertEquals(0, getAllSetups().size()); - } - - @Test - public void shouldCopyLearnerSetup() { - final LearnerSetup ls = learnerSetupApi.create(project.getId(), createDefaultLearnerSetup(), jwt) - .readEntity(LearnerSetup.class); - - final Response res = learnerSetupApi.copy(project.getId(), ls.getId(), jwt); - assertEquals(HttpStatus.OK.value(), res.getStatus()); - assertEquals(2, getAllSetups().size()); - - final LearnerSetup copiedSetup = res.readEntity(LearnerSetup.class); - compareTo(ls, copiedSetup); - } - - @Test - public void shouldNotChangeSavedFlag() { - final LearnerSetup ls = learnerSetupApi.create(project.getId(), createDefaultLearnerSetup(), jwt) - .readEntity(LearnerSetup.class); - - ls.setSaved(false); - - final Response res = learnerSetupApi.update(project.getId(), ls.getId(), ls, jwt); - assertEquals(HttpStatus.OK.value(), res.getStatus()); - assertEquals(1, getAllSetups().size()); - - final LearnerSetup updatedSetup = res.readEntity(LearnerSetup.class); - assertTrue(updatedSetup.isSaved()); - } - - private List getAllSetups() { - return learnerSetupApi.getAll(project.getId(), jwt) - .readEntity(new GenericType<>() { - }); - } - - private void compareTo(LearnerSetup ls1, LearnerSetup ls2) { - assertNotNull(ls2.getId()); - assertNotNull(ls2.getWebDriver()); - assertNotNull(ls2.getAlgorithm()); - assertNotNull(ls2.getEquivalenceOracle()); - assertTrue(ls2.isSaved()); - - assertEquals(ls1.getName(), ls2.getName()); - assertEquals(ls1.isEnableCache(), ls2.isEnableCache()); - assertEquals(ls1.getPreSymbol().getSymbol().getId(), ls2.getPreSymbol().getSymbol().getId()); - for (ParameterizedSymbol ps : ls1.getSymbols()) { - assertEquals(1, ls2.getSymbols().stream() - .filter(s -> s.getSymbol().getId().equals(ps.getSymbol().getId())) - .count()); - } - } - - private LearnerSetup createDefaultLearnerSetup() { - final LearnerSetup ls = new LearnerSetup(); - ls.setProject(project); - ls.setEnvironments(project.getEnvironments()); - ls.setEnableCache(true); - ls.setName("testSetup"); - ls.setAlgorithm(new TTT()); - final var webDriverConfig = new WebDriverConfig(); - webDriverConfig.setBrowser("chrome"); - ls.setWebDriver(webDriverConfig); - ls.setEquivalenceOracle(new MealyRandomWordsEQOracleProxy()); - ls.setPreSymbol(new ParameterizedSymbol(symbols.get(0))); - ls.setSymbols(symbols.stream() - .map(ParameterizedSymbol::new) - .collect(Collectors.toList())); - return ls; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static abstract class IgnoreLearnerResultFieldsMixin { - @JsonIgnore - abstract void setStatistics(Statistics statistics); - - @JsonIgnore - @JsonProperty("error") - abstract void setError(Boolean error); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static abstract class IgnoreLearnerResultStepFieldsMixin { - @JsonIgnore - abstract void setStatistics(Statistics statistics); - - @JsonIgnore - @JsonProperty("error") - abstract void setError(boolean error); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static abstract class IgnoreLearnerStatusFieldsMixin { - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/LtsFormulaResourceIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/LtsFormulaResourceIT.java deleted file mode 100644 index f1b2810dc..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/LtsFormulaResourceIT.java +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources; - -import static org.hibernate.validator.internal.util.Contracts.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import com.jayway.jsonpath.JsonPath; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.integrationtests.resources.api.LtsFormulaApi; -import de.learnlib.alex.integrationtests.resources.api.LtsFormulaSuiteApi; -import de.learnlib.alex.integrationtests.resources.api.ProjectApi; -import de.learnlib.alex.integrationtests.resources.api.UserApi; -import de.learnlib.alex.modelchecking.entities.LtsFormula; -import de.learnlib.alex.modelchecking.entities.LtsFormulaSuite; -import java.util.Arrays; -import java.util.List; -import javax.ws.rs.core.GenericType; -import javax.ws.rs.core.Response; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.http.HttpStatus; - -public class LtsFormulaResourceIT extends AbstractResourceIT { - - private String jwtUser1; - - private String jwtUser2; - - private Long projectId1; - - private Long projectId2; - - private LtsFormulaApi formulaApi; - private LtsFormulaSuiteApi formulaSuiteApi; - - private LtsFormulaSuite suite1; - private LtsFormulaSuite suite2; - - @BeforeEach - public void before() { - this.formulaApi = new LtsFormulaApi(client, port); - - final UserApi userApi = new UserApi(client, port); - final ProjectApi projectApi = new ProjectApi(client, port); - formulaSuiteApi = new LtsFormulaSuiteApi(client, port); - - userApi.create("{\"email\":\"test1@test.de\",\"username\":\"test1\",\"password\":\"test\"}"); - userApi.create("{\"email\":\"test2@test.de\",\"username\":\"test2\",\"password\":\"test\"}"); - jwtUser1 = userApi.login("test1@test.de", "test"); - jwtUser2 = userApi.login("test2@test.de", "test"); - - projectId1 = projectApi.create("{\"name\":\"test\",\"url\":\"http://localhost:8080/"}", jwtUser1) - .readEntity(Project.class) - .getId(); - - projectId2 = projectApi.create("{\"name\":\"test\",\"url\":\"http://localhost:8080/"}", jwtUser2) - .readEntity(Project.class) - .getId(); - - final LtsFormulaSuite suite = new LtsFormulaSuite(); - suite.setName("default"); - - this.suite1 = formulaSuiteApi.create(projectId1, suite, jwtUser1) - .readEntity(LtsFormulaSuite.class); - - this.suite2 = formulaSuiteApi.create(projectId2, suite, jwtUser2) - .readEntity(LtsFormulaSuite.class); - } - - @Test - public void shouldCreateAFormula() throws Exception { - final LtsFormula formula = new LtsFormula(); - formula.setName("test"); - formula.setFormula("<>true"); - - final Response res = formulaApi.create(projectId1, suite1.getId(), formula, jwtUser1); - assertEquals(Response.Status.CREATED.getStatusCode(), res.getStatus()); - - final String json = res.readEntity(String.class); - JsonPath.read(json, "$.id"); - - assertEquals(1, getNumberOfFormulas(projectId1, suite1.getId(), jwtUser1)); - } - - @Test - public void shouldCreateAFormulaWithoutName() throws Exception { - final LtsFormula formula = new LtsFormula(); - formula.setFormula("<>true"); - - final Response res = formulaApi.create(projectId1, suite1.getId(), formula, jwtUser1); - assertEquals(Response.Status.CREATED.getStatusCode(), res.getStatus()); - - final LtsFormula createdFormula = res.readEntity(LtsFormula.class); - assertNotNull(createdFormula.getId()); - assertEquals(formula.getFormula(), createdFormula.getFormula()); - assertEquals(formula.getName(), createdFormula.getName()); - - assertEquals(1, getNumberOfFormulas(projectId1, suite1.getId(), jwtUser1)); - } - - @Test - public void shouldFailToCreateFormulaWithoutFormula() throws Exception { - final LtsFormula formula = new LtsFormula(); - formula.setName("test"); - - final Response res = formulaApi.create(projectId1, suite1.getId(), formula, jwtUser1); - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), res.getStatus()); - assertEquals(0, getNumberOfFormulas(projectId1, suite1.getId(), jwtUser1)); - } - - @Test - public void shouldFailToCreateFormulaWithInvalidFormula() throws Exception { - final LtsFormula formula = new LtsFormula(); - formula.setName("test"); - formula.setFormula("invalid"); - - final Response res = formulaApi.create(projectId1, suite1.getId(), formula, jwtUser1); - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), res.getStatus()); - assertEquals(0, getNumberOfFormulas(projectId1, suite1.getId(), jwtUser1)); - } - - @Test - public void shouldNotCreateFormulaInAnotherUsersProject() throws Exception { - final LtsFormula formula = new LtsFormula(); - formula.setName("test"); - formula.setFormula("<>true"); - - final Response res = formulaApi.create(projectId2, suite2.getId(), formula, jwtUser1); - assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), res.getStatus()); - assertEquals(0, getNumberOfFormulas(projectId1, suite1.getId(), jwtUser1)); - assertEquals(0, getNumberOfFormulas(projectId2, suite2.getId(), jwtUser2)); - } - - @Test - public void shouldDeleteFormula() throws Exception { - final LtsFormula formula = createFormula(projectId1, suite1.getId(), "test", "<>true", jwtUser1); - final Response res = formulaApi.delete(projectId1, suite1.getId(), formula.getId(), jwtUser1); - assertEquals(Response.Status.NO_CONTENT.getStatusCode(), res.getStatus()); - assertEquals(0, getNumberOfFormulas(projectId1, suite1.getId(), jwtUser1)); - } - - @Test - public void shouldFailToDeleteNonExistingFormula() { - final Response res = formulaApi.delete(projectId1, suite1.getId(), -1L, jwtUser1); - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), res.getStatus()); - } - - @Test - public void shouldFailToDeleteFormulaOfAnotherUser() throws Exception { - final LtsFormula formula = createFormula(projectId1, suite1.getId(), "test", "<>true", jwtUser1); - final Response res = formulaApi.delete(projectId2, suite1.getId(), formula.getId(), jwtUser2); - assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), res.getStatus()); - assertEquals(1, getNumberOfFormulas(projectId1, suite1.getId(), jwtUser1)); - } - - @Test - public void shouldDeleteMultipleFormulas() throws Exception { - final List ids = Arrays.asList( - createFormula(projectId1, suite1.getId(), "test", "<> true", jwtUser1).getId(), - createFormula(projectId1, suite1.getId(), "test", "<> true", jwtUser1).getId() - ); - final Response res = formulaApi.delete(projectId1, suite1.getId(), ids, jwtUser1); - assertEquals(Response.Status.NO_CONTENT.getStatusCode(), res.getStatus()); - assertEquals(0, getNumberOfFormulas(projectId1, suite1.getId(), jwtUser1)); - } - - @Test - public void shouldFailToDeleteMultipleFormulasIfOneDoesNotExist() throws Exception { - final List ids = Arrays.asList( - createFormula(projectId1, suite1.getId(), "test", "<> true", jwtUser1).getId(), - createFormula(projectId1, suite1.getId(), "test", "<> true", jwtUser1).getId() - - 1 - ); - final Response res = formulaApi.delete(projectId1, suite1.getId(), ids, jwtUser1); - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), res.getStatus()); - assertEquals(2, getNumberOfFormulas(projectId1, suite1.getId(), jwtUser1)); - } - - @Test - public void shouldUpdateAFormula() throws Exception { - final LtsFormula formula = createFormula(projectId1, suite1.getId(), "test", "<> true", jwtUser1); - formula.setName("newName"); - formula.setFormula("<>false"); - - final Response res = formulaApi.update(projectId1, suite1.getId(), formula.getId(), formula, jwtUser1); - assertEquals(Response.Status.OK.getStatusCode(), res.getStatus()); - - final LtsFormula updatedFormula = res.readEntity(LtsFormula.class); - assertEquals(formula.getId(), updatedFormula.getId()); - assertEquals(formula.getName(), updatedFormula.getName()); - assertEquals(formula.getFormula(), updatedFormula.getFormula()); - - assertEquals(1, getNumberOfFormulas(projectId1, suite1.getId(), jwtUser1)); - } - - @Test - public void shouldFailToUpdateIfFormulaIsEmpty() { - shouldFailToUpdate(projectId1, "test", "<>true", "newName", "", jwtUser1); - } - - @Test - public void shouldFailToUpdateIfFormulaIsInvalid() { - shouldFailToUpdate(projectId1, "test", "<>true", "newName", "invalid", jwtUser1); - } - - @Test - public void shouldMoveFormulaToAnotherSuite() { - LtsFormulaSuite s1 = createFormulaSuite(projectId1, "s1", jwtUser1); - LtsFormulaSuite s2 = createFormulaSuite(projectId1, "s2", jwtUser1); - - LtsFormula formula = createFormula(projectId1, s1.getId(), "test", "true", jwtUser1); - - final Response res = formulaApi.updateSuite(projectId1, s1.getId(), formula.getId(), s2, jwtUser1); - assertEquals(HttpStatus.OK.value(), res.getStatus()); - formula = res.readEntity(LtsFormula.class); - assertEquals(s2.getId(), formula.getSuiteId()); - } - - @Test - public void shouldMoveMultipleFormulasToAnotherSuite() throws Exception { - LtsFormulaSuite s1 = createFormulaSuite(projectId1, "s1", jwtUser1); - LtsFormulaSuite s2 = createFormulaSuite(projectId1, "s2", jwtUser1); - - LtsFormula f1 = createFormula(projectId1, s1.getId(), "test", "true", jwtUser1); - LtsFormula f2 = createFormula(projectId1, s1.getId(), "test", "true", jwtUser1); - - final Response res = formulaApi.updateSuite(projectId1, s1.getId(), Arrays.asList(f1.getId(), f2.getId()), s2, jwtUser1); - assertEquals(HttpStatus.OK.value(), res.getStatus()); - - final List updatedFormulas = res.readEntity(new GenericType<>() { - }); - for (LtsFormula f : updatedFormulas) { - assertEquals(s2.getId(), f.getSuiteId()); - } - - assertEquals(0, getNumberOfFormulas(projectId1, s1.getId(), jwtUser1)); - assertEquals(2, getNumberOfFormulas(projectId1, s2.getId(), jwtUser1)); - } - - private void shouldFailToUpdate(Long projectId, String name, String formula, String newName, String newFormula, String jwt) { - final LtsFormula ltlFormula = createFormula(projectId1, suite1.getId(), name, formula, jwtUser1); - ltlFormula.setName(newName); - ltlFormula.setFormula(newFormula); - - final Response res = formulaApi.update(projectId, suite1.getId(), ltlFormula.getId(), ltlFormula, jwt); - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), res.getStatus()); - - final LtsFormula f = formulaSuiteApi.get(projectId1, suite1.getId(), jwt) - .readEntity(LtsFormulaSuite.class) - .getFormulas() - .stream() - .filter(l -> l.getId().equals(ltlFormula.getId())) - .findFirst() - .orElse(null); - - assertNotNull(f); - assertEquals(name, f.getName()); - assertEquals(formula, f.getFormula()); - } - - private LtsFormula createFormula(Long projectId, Long suiteId, String name, String formula, String jwt) { - final LtsFormula f = new LtsFormula(); - f.setName(name); - f.setFormula(formula); - - return formulaApi.create(projectId, suiteId, f, jwt) - .readEntity(LtsFormula.class); - } - - private LtsFormulaSuite createFormulaSuite(Long projectId, String name, String jwt) { - final LtsFormulaSuite suite = new LtsFormulaSuite(); - suite.setName(name); - return formulaSuiteApi.create(projectId, suite, jwt) - .readEntity(LtsFormulaSuite.class); - } - - private int getNumberOfFormulas(Long projectId1, Long suiteId, String jwt) throws Exception { - return formulaSuiteApi.get(projectId1, suiteId, jwt) - .readEntity(LtsFormulaSuite.class) - .getFormulas() - .size(); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/LtsFormulaSuiteResourceIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/LtsFormulaSuiteResourceIT.java deleted file mode 100644 index 67b40dbfd..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/LtsFormulaSuiteResourceIT.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.integrationtests.SpringRestError; -import de.learnlib.alex.integrationtests.resources.api.LtsFormulaApi; -import de.learnlib.alex.integrationtests.resources.api.LtsFormulaSuiteApi; -import de.learnlib.alex.integrationtests.resources.api.ProjectApi; -import de.learnlib.alex.integrationtests.resources.api.UserApi; -import de.learnlib.alex.modelchecking.entities.LtsFormula; -import de.learnlib.alex.modelchecking.entities.LtsFormulaSuite; -import java.util.Arrays; -import java.util.List; -import javax.ws.rs.core.GenericType; -import javax.ws.rs.core.Response; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.http.HttpStatus; - -public class LtsFormulaSuiteResourceIT extends AbstractResourceIT { - - private LtsFormulaSuiteApi formulaSuiteApi; - private LtsFormulaApi formulaApi; - - private Project project; - private String jwt; - - @BeforeEach - public void before() { - final UserApi userApi = new UserApi(client, port); - final ProjectApi projectApi = new ProjectApi(client, port); - - formulaApi = new LtsFormulaApi(client, port); - formulaSuiteApi = new LtsFormulaSuiteApi(client, port); - - jwt = userApi.login(ADMIN_EMAIL, ADMIN_PASSWORD); - - project = projectApi.create("{\"name\":\"test\",\"url\":\"http://localhost:8080/"}", jwt) - .readEntity(Project.class); - } - - @Test - public void createFormulaSuite() { - final LtsFormulaSuite suite = new LtsFormulaSuite(); - suite.setName("test"); - - final Response res = formulaSuiteApi.create(project.getId(), suite, jwt); - assertEquals(HttpStatus.CREATED.value(), res.getStatus()); - final LtsFormulaSuite createdSuite = res.readEntity(LtsFormulaSuite.class); - assertFormulaSuite(createdSuite, "test", 0); - } - - @Test - public void shouldNotCreateFormulaSuiteWithSameNameTwice() { - final LtsFormulaSuite suite1 = new LtsFormulaSuite(); - suite1.setName("test"); - formulaSuiteApi.create(project.getId(), suite1, jwt); - - final LtsFormulaSuite suite2 = new LtsFormulaSuite(); - suite2.setName("test"); - final Response res = formulaSuiteApi.create(project.getId(), suite2, jwt); - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - res.readEntity(SpringRestError.class); - assertEquals(1, getNumberOfFormulaSuites(project.getId(), jwt)); - } - - @Test - public void shouldDeleteEmptyFormulaSuite() { - final LtsFormulaSuite suite = createFormulaSuite(project.getId(), "test", jwt); - final Response res = formulaSuiteApi.delete(project.getId(), suite.getId(), jwt); - assertEquals(HttpStatus.NO_CONTENT.value(), res.getStatus()); - assertEquals(0, getNumberOfFormulaSuites(project.getId(), jwt)); - } - - @Test - public void shouldDeleteNonEmptyFormulaSuite() { - LtsFormulaSuite suite = createFormulaSuite(project.getId(), "test", jwt); - createFormula(project.getId(), suite.getId(), "f1", "[]true", jwt); - createFormula(project.getId(), suite.getId(), "f2", "[]false", jwt); - - suite = formulaSuiteApi.get(project.getId(), suite.getId(), jwt) - .readEntity(LtsFormulaSuite.class); - - assertFormulaSuite(suite, "test", 2); - - final Response res = formulaSuiteApi.delete(project.getId(), suite.getId(), jwt); - assertEquals(HttpStatus.NO_CONTENT.value(), res.getStatus()); - assertEquals(0, getNumberOfFormulaSuites(project.getId(), jwt)); - } - - @Test - public void shouldDeleteMultipleFormulaSuites() { - final LtsFormulaSuite suite1 = createFormulaSuite(project.getId(), "test1", jwt); - final LtsFormulaSuite suite2 = createFormulaSuite(project.getId(), "test2", jwt); - - final Response res = formulaSuiteApi.deleteAll(project.getId(), Arrays.asList(suite1.getId(), suite2.getId()), jwt); - assertEquals(HttpStatus.NO_CONTENT.value(), res.getStatus()); - assertEquals("", res.readEntity(String.class)); - assertEquals(0, getNumberOfFormulaSuites(project.getId(), jwt)); - } - - @Test - public void shouldFailToDeleteSuiteWithNonExistingId() { - final LtsFormulaSuite suite1 = createFormulaSuite(project.getId(), "test1", jwt); - - final Response res = formulaSuiteApi.deleteAll(project.getId(), Arrays.asList(suite1.getId(), -1L), jwt); - assertEquals(HttpStatus.NOT_FOUND.value(), res.getStatus()); - res.readEntity(SpringRestError.class); - assertEquals(1, getNumberOfFormulaSuites(project.getId(), jwt)); - } - - @Test - public void shouldUpdateName() { - final LtsFormulaSuite suite = createFormulaSuite(project.getId(), "test1", jwt); - suite.setName("updatedName"); - - final Response res = formulaSuiteApi.update(project.getId(), suite.getId(), suite, jwt); - assertEquals(HttpStatus.OK.value(), res.getStatus()); - - final LtsFormulaSuite updatedSuite = res.readEntity(LtsFormulaSuite.class); - assertFormulaSuite(updatedSuite, "updatedName", 0); - } - - @Test - public void shouldNotUpdateNameIfNameExists() { - createFormulaSuite(project.getId(), "test", jwt); - - LtsFormulaSuite suite = createFormulaSuite(project.getId(), "newSuite", jwt); - suite.setName("test"); - - final Response res = formulaSuiteApi.update(project.getId(), suite.getId(), suite, jwt); - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - res.readEntity(SpringRestError.class); - - suite = formulaSuiteApi.get(project.getId(), suite.getId(), jwt).readEntity(LtsFormulaSuite.class); - assertFormulaSuite(suite, "newSuite", 0); - } - - private LtsFormulaSuite createFormulaSuite(Long projectId, String name, String jwt) { - final LtsFormulaSuite suite = new LtsFormulaSuite(); - suite.setName(name); - - return formulaSuiteApi.create(projectId, suite, jwt) - .readEntity(LtsFormulaSuite.class); - } - - private LtsFormula createFormula(Long projectId, Long suiteId, String name, String formula, String jwt) { - final LtsFormula f = new LtsFormula(); - f.setName(name); - f.setFormula(formula); - - return formulaApi.create(projectId, suiteId, f, jwt) - .readEntity(LtsFormula.class); - } - - private void assertFormulaSuite(LtsFormulaSuite suite, String name, int numberOfFormulas) { - assertNotNull(suite.getId()); - assertNotNull(suite.getProject()); - assertEquals(name, suite.getName()); - assertEquals(numberOfFormulas, suite.getFormulas().size()); - } - - private int getNumberOfFormulaSuites(Long projectId, String jwt) { - return formulaSuiteApi.getAll(projectId, jwt) - .readEntity(new GenericType>() { - }) - .size(); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/ProjectEnvironmentResourceIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/ProjectEnvironmentResourceIT.java deleted file mode 100644 index f846f0abf..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/ProjectEnvironmentResourceIT.java +++ /dev/null @@ -1,541 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.data.entities.ProjectEnvironmentVariable; -import de.learnlib.alex.data.entities.ProjectUrl; -import de.learnlib.alex.integrationtests.SpringRestError; -import de.learnlib.alex.integrationtests.resources.api.ProjectApi; -import de.learnlib.alex.integrationtests.resources.api.ProjectEnvironmentApi; -import de.learnlib.alex.integrationtests.resources.api.UserApi; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import javax.ws.rs.core.GenericType; -import javax.ws.rs.core.Response; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.http.HttpStatus; - -public class ProjectEnvironmentResourceIT extends AbstractResourceIT { - - private ProjectEnvironmentApi envApi; - - private ProjectApi projectApi; - - private String adminJwt; - - private String memberJwt; - - private Project project; - - @BeforeEach - public void pre() { - final UserApi userApi = new UserApi(client, port); - projectApi = new ProjectApi(client, port); - envApi = new ProjectEnvironmentApi(client, port); - - adminJwt = userApi.login("admin@alex.example", "admin"); - - final User member = userApi.create("{\"email\":\"test@test.de\",\"username\":\"test\",\"password\":\"test\"}") - .readEntity(User.class); - - memberJwt = userApi.login("test@test.de", "test"); - - final Response res2 = projectApi.create("{\"name\":\"test\",\"url\":\"http://localhost:8080/"}", adminJwt); - project = res2.readEntity(Project.class); - - projectApi.addMembers(project.getId(), Collections.singletonList(member.getId()), adminJwt); - } - - @Test - public void shouldCreateNewEnvironment() { - final ProjectEnvironment env = new ProjectEnvironment(); - env.setName("test"); - - final Response res = envApi.create(project.getId(), env, adminJwt); - assertEquals(HttpStatus.CREATED.value(), res.getStatus()); - - final ProjectEnvironment createdEnvironment = res.readEntity(ProjectEnvironment.class); - assertNotNull(createdEnvironment.getId()); - assertEquals("test", createdEnvironment.getName()); - assertEquals(1, createdEnvironment.getUrls().size()); - } - - @Test - public void shouldNotCreateEnvironmentWithSameName() { - final ProjectEnvironment env1 = new ProjectEnvironment(); - env1.setName("test"); - - final ProjectEnvironment env2 = new ProjectEnvironment(); - env2.setName("test"); - - envApi.create(project.getId(), env1, adminJwt); - final Response res = envApi.create(project.getId(), env2, adminJwt); - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - res.readEntity(SpringRestError.class); - assertEquals(2, countEnvironments()); - } - - @Test - public void newEnvironmentShouldHaveSameUrlsAsTheDefaultOne() { - final ProjectEnvironment env1 = new ProjectEnvironment(); - env1.setName("test"); - - ProjectEnvironment initialEnvironment = project.getEnvironments().get(0); - final ProjectUrl newUrl = new ProjectUrl(); - newUrl.setName("url2"); - newUrl.setUrl("http://url2/"); - envApi.createUrl(project.getId(), initialEnvironment.getId(), newUrl, adminJwt); - initialEnvironment = getById(initialEnvironment.getId()); - - final ProjectEnvironment createdEnvironment = envApi.create(project.getId(), env1, adminJwt) - .readEntity(ProjectEnvironment.class); - - assertUrlsAreTheSame(initialEnvironment, createdEnvironment); - } - - @Test - public void newEnvironmentShouldHaveSameVariablesAsTheDefaultOne() { - final ProjectEnvironment env1 = new ProjectEnvironment(); - env1.setName("test"); - - ProjectEnvironment initialEnvironment = project.getEnvironments().get(0); - final ProjectEnvironmentVariable variable = new ProjectEnvironmentVariable(); - variable.setName("var"); - variable.setValue("test"); - envApi.createVariable(project.getId(), initialEnvironment.getId(), variable, adminJwt); - initialEnvironment = getById(initialEnvironment.getId()); - - final ProjectEnvironment createdEnvironment = envApi.create(project.getId(), env1, adminJwt) - .readEntity(ProjectEnvironment.class); - - assertVariablesAreTheSame(initialEnvironment, createdEnvironment); - } - - @Test - public void updatingUrlNameShouldUpdateAllUrlNames() { - final List environments = createEnvironments(); - ProjectEnvironment env1 = environments.get(0); - ProjectEnvironment env2 = environments.get(1); - - final ProjectUrl urlToUpdate = env1.getUrls().get(env1.getUrls().size() - 1); - urlToUpdate.setName("teeeest"); - final Response res3 = envApi.updateUrl(project.getId(), env1.getId(), urlToUpdate.getId(), urlToUpdate, adminJwt); - - assertEquals(HttpStatus.OK.value(), res3.getStatus()); - env2 = getById(env2.getId()); - - assertUrlsAreTheSame(env1, env2); - } - - @Test - public void updatingVariableNameShouldUpdateAllVariableNames() { - final List environments = createEnvironments(); - ProjectEnvironment env1 = environments.get(0); - ProjectEnvironment env2 = environments.get(1); - - final ProjectEnvironmentVariable variableToUpdate = env1.getVariables().get(env1.getVariables().size() - 1); - variableToUpdate.setName("teeeest"); - final Response res3 = envApi.updateVariable(project.getId(), env1.getId(), variableToUpdate.getId(), variableToUpdate, adminJwt); - - assertEquals(HttpStatus.OK.value(), res3.getStatus()); - env2 = getById(env2.getId()); - - assertVariablesAreTheSame(env1, env2); - } - - @Test - public void deletingUrlDeletesUrlInAllEnvironments() { - final List environments = createEnvironments(); - ProjectEnvironment env1 = environments.get(0); - ProjectEnvironment env2 = environments.get(1); - - final ProjectUrl urlToDelete = env1.getUrls().get(env1.getUrls().size() - 1); - final Response res3 = envApi.deleteUrl(project.getId(), env1.getId(), urlToDelete.getId(), adminJwt); - - assertEquals(HttpStatus.NO_CONTENT.value(), res3.getStatus()); - - final ProjectEnvironment env1Post = getById(env1.getId()); - final ProjectEnvironment env2Post = getById(env2.getId()); - - assertEquals(env1.getUrls().size() - 1, env1Post.getUrls().size()); - assertEquals(env2.getUrls().size() - 1, env2Post.getUrls().size()); - assertTrue(env1Post.getUrls().stream().noneMatch(v -> v.getName().equals(urlToDelete.getName()))); - assertVariablesAreTheSame(env1Post, env2Post); - } - - @Test - public void deletingVariablesDeletesVariableInAllEnvironments() { - final List environments = createEnvironments(); - ProjectEnvironment env1 = environments.get(0); - ProjectEnvironment env2 = environments.get(1); - - final ProjectEnvironmentVariable variableToDelete = env1.getVariables().get(env1.getVariables().size() - 1); - final Response res3 = envApi.deleteVariable(project.getId(), env1.getId(), variableToDelete.getId(), adminJwt); - - assertEquals(HttpStatus.NO_CONTENT.value(), res3.getStatus()); - - final ProjectEnvironment env1Post = getById(env1.getId()); - final ProjectEnvironment env2Post = getById(env2.getId()); - - assertEquals(env1.getVariables().size() - 1, env1Post.getVariables().size()); - assertEquals(env2.getVariables().size() - 1, env2Post.getVariables().size()); - assertTrue(env1Post.getVariables().stream().noneMatch(v -> v.getName().equals(variableToDelete.getName()))); - assertVariablesAreTheSame(env1Post, env2Post); - } - - private List createEnvironments() { - ProjectEnvironment env1 = project.getDefaultEnvironment(); - - final ProjectUrl url = new ProjectUrl(); - url.setName("url1"); - url.setUrl("http://asd/"); - envApi.createUrl(project.getId(), env1.getId(), url, adminJwt); - - final ProjectEnvironmentVariable variable1 = new ProjectEnvironmentVariable(); - variable1.setName("var1"); - variable1.setValue("test1"); - envApi.createVariable(project.getId(), env1.getId(), variable1, adminJwt); - - final ProjectEnvironmentVariable variable2 = new ProjectEnvironmentVariable(); - variable1.setName("var2"); - variable1.setValue("test2"); - envApi.createVariable(project.getId(), env1.getId(), variable2, adminJwt); - - env1 = getById(env1.getId()); - - ProjectEnvironment env2 = new ProjectEnvironment(); - env2.setProject(project); - env2.setName("env2"); - final Response res1 = envApi.create(project.getId(), env2, adminJwt); - env2 = res1.readEntity(ProjectEnvironment.class); - - assertVariablesAreTheSame(env1, env2); - assertUrlsAreTheSame(env1, env2); - - return Arrays.asList(env1, env2); - } - - @Test - public void shouldNotDeleteLastUrlInEnvironment() { - final ProjectEnvironment environment = project.getDefaultEnvironment(); - final ProjectUrl url = environment.getUrls().get(0); - final Response res = envApi.deleteUrl(project.getId(), environment.getId(), url.getId(), adminJwt); - - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - assertEquals(environment.getUrls().size(), getById(environment.getId()).getUrls().size()); - } - - @Test - public void shouldNotDeleteTheLastEnvironment() { - final Long envId = project.getEnvironments().get(0).getId(); - final Response res = envApi.delete(project.getId(), envId, adminJwt); - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - res.readEntity(SpringRestError.class); - - final Project p = projectApi.get(project.getId(), adminJwt).readEntity(Project.class); - assertEquals(1, p.getEnvironments().size()); - } - - @Test - public void shouldMakeAnotherEnvironmentDefaultWhenDeletingDefaultEnvironment() { - final ProjectEnvironment env = new ProjectEnvironment(); - env.setName("env2"); - - envApi.create(project.getId(), env, adminJwt); - project = projectApi.get(project.getId(), adminJwt).readEntity(Project.class); - - final Long defaultEnvId = project.getDefaultEnvironment().getId(); - final Response res = envApi.delete(project.getId(), defaultEnvId, adminJwt); - project = projectApi.get(project.getId(), adminJwt).readEntity(Project.class); - - assertEquals(HttpStatus.NO_CONTENT.value(), res.getStatus()); - assertEquals(1, project.getEnvironments().size()); - assertNotEquals(defaultEnvId, project.getDefaultEnvironment().getId()); - } - - @Test - public void shouldNotUpdateEnvironmentIfNameExists() { - ProjectEnvironment env2 = new ProjectEnvironment(); - env2.setName("env2"); - - ProjectEnvironment env3 = new ProjectEnvironment(); - env3.setName("env3"); - - env2 = envApi.create(project.getId(), env2, adminJwt).readEntity(ProjectEnvironment.class); - env3 = envApi.create(project.getId(), env3, adminJwt).readEntity(ProjectEnvironment.class); - - env2.setName("env3"); - final Response res = envApi.update(project.getId(), env2.getId(), env2, adminJwt); - project = projectApi.get(project.getId(), adminJwt).readEntity(Project.class); - - env2 = project.getEnvironments().stream().filter(e -> e.getName().equals("env2")).findFirst().orElse(null); - env3 = project.getEnvironments().stream().filter(e -> e.getName().equals("env3")).findFirst().orElse(null); - - res.readEntity(SpringRestError.class); - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - assertNotNull(env2); - assertNotNull(env3); - } - - @Test - public void shouldMakeAnotherEnvironmentTheDefaultOne() { - ProjectEnvironment env2 = new ProjectEnvironment(); - env2.setName("env2"); - env2 = envApi.create(project.getId(), env2, adminJwt).readEntity(ProjectEnvironment.class); - - env2.setDefault(true); - env2 = envApi.update(project.getId(), env2.getId(), env2, adminJwt).readEntity(ProjectEnvironment.class); - - project = projectApi.get(project.getId(), adminJwt).readEntity(Project.class); - - assertEquals(env2.getId(), project.getDefaultEnvironment().getId()); - assertEquals(1, project.getEnvironments().stream().filter(ProjectEnvironment::isDefault).count()); - } - - @Test - public void shouldNotCreateVariableIfNameExists() { - final ProjectEnvironment env = project.getDefaultEnvironment(); - - final ProjectEnvironmentVariable var1 = new ProjectEnvironmentVariable(); - var1.setName("var1"); - var1.setValue("test"); - - envApi.createVariable(project.getId(), env.getId(), var1, adminJwt); - - final ProjectEnvironmentVariable var2 = new ProjectEnvironmentVariable(); - var2.setName("var1"); - var2.setValue("test"); - - final Response res = envApi.createVariable(project.getId(), env.getId(), var1, adminJwt); - project = projectApi.get(project.getId(), adminJwt).readEntity(Project.class); - - res.readEntity(SpringRestError.class); - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - assertEquals(1, project.getDefaultEnvironment().getVariables().size()); - assertEquals("var1", project.getDefaultEnvironment().getVariables().get(0).getName()); - } - - @Test - public void shouldNotUpdateVariableWithExistingName() { - ProjectEnvironmentVariable var1 = new ProjectEnvironmentVariable(); - var1.setName("var1"); - var1.setValue("test"); - - ProjectEnvironmentVariable var2 = new ProjectEnvironmentVariable(); - var2.setName("var2"); - var2.setValue("test"); - - var1 = envApi.createVariable(project.getId(), project.getDefaultEnvironment().getId(), var1, adminJwt) - .readEntity(ProjectEnvironmentVariable.class); - var2 = envApi.createVariable(project.getId(), project.getDefaultEnvironment().getId(), var2, adminJwt) - .readEntity(ProjectEnvironmentVariable.class); - - var2.setName("var1"); - - final Response res = envApi.updateVariable(project.getId(), project.getDefaultEnvironment().getId(), var2.getId(), var2, adminJwt); - project = projectApi.get(project.getId(), adminJwt).readEntity(Project.class); - - res.readEntity(SpringRestError.class); - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - assertEquals(1, project.getDefaultEnvironment().getVariables().stream().filter(v -> v.getName().equals("var1")).count()); - assertEquals(1, project.getDefaultEnvironment().getVariables().stream().filter(v -> v.getName().equals("var2")).count()); - } - - @Test - public void memberShouldNotCreateNewEnvironment() { - final ProjectEnvironment env = new ProjectEnvironment(); - env.setName("test"); - - final Response res = envApi.create(project.getId(), env, memberJwt); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res.getStatus()); - } - - @Test - public void shouldNotUpdateEnvironmentAsMember() { - final ProjectEnvironment env = new ProjectEnvironment(); - env.setName("test"); - - final Response res1 = envApi.create(project.getId(), env, adminJwt); - final ProjectEnvironment createdEnvironment = res1.readEntity(ProjectEnvironment.class); - - createdEnvironment.setName("test1"); - - final Response res2 = envApi.update(project.getId(), createdEnvironment.getId(), createdEnvironment, memberJwt); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res2.getStatus()); - } - - @Test - public void shouldNotDeleteEnvironmentAsMember() { - final ProjectEnvironment env = new ProjectEnvironment(); - env.setName("test"); - - final Response res1 = envApi.create(project.getId(), env, adminJwt); - final ProjectEnvironment createdEnvironment = res1.readEntity(ProjectEnvironment.class); - - final Response res2 = envApi.delete(project.getId(), createdEnvironment.getId(), memberJwt); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res2.getStatus()); - } - - @Test - public void shouldNotCreateUrlAsMember() { - final ProjectEnvironment env = new ProjectEnvironment(); - env.setName("test"); - - final Response res1 = envApi.create(project.getId(), env, adminJwt); - final ProjectEnvironment createdEnvironment = res1.readEntity(ProjectEnvironment.class); - - final ProjectUrl newUrl = new ProjectUrl(); - newUrl.setName("url2"); - newUrl.setUrl("http://url2/"); - - final Response res2 = envApi.createUrl(project.getId(), createdEnvironment.getId(), newUrl, memberJwt); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res2.getStatus()); - } - - @Test - public void shouldNotUpdateUrlAsMember() { - final ProjectEnvironment env = new ProjectEnvironment(); - env.setName("test"); - - final Response res1 = envApi.create(project.getId(), env, adminJwt); - final ProjectEnvironment createdEnvironment = res1.readEntity(ProjectEnvironment.class); - - final ProjectUrl urlToUpdate = createdEnvironment.getUrls().get(0); - urlToUpdate.setName("testttttt"); - - final Response res2 = envApi.updateUrl(project.getId(), createdEnvironment.getId(), urlToUpdate.getId(), urlToUpdate, memberJwt); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res2.getStatus()); - } - - @Test - public void shouldNotDeleteUrlAsMember() { - final ProjectEnvironment env = new ProjectEnvironment(); - env.setName("test"); - - final Response res1 = envApi.create(project.getId(), env, adminJwt); - final ProjectEnvironment createdEnvironment = res1.readEntity(ProjectEnvironment.class); - - final ProjectUrl urlToDelete = createdEnvironment.getUrls().get(0); - - final Response res2 = envApi.deleteUrl(project.getId(), createdEnvironment.getId(), urlToDelete.getId(), memberJwt); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res2.getStatus()); - } - - @Test - public void shouldNotCreateVariableAsMember() { - final ProjectEnvironment env = new ProjectEnvironment(); - env.setName("test"); - - final Response res1 = envApi.create(project.getId(), env, adminJwt); - final ProjectEnvironment createdEnvironment = res1.readEntity(ProjectEnvironment.class); - - final ProjectEnvironmentVariable var1 = new ProjectEnvironmentVariable(); - var1.setName("var1"); - var1.setValue("test"); - - final Response res2 = envApi.createVariable(project.getId(), createdEnvironment.getId(), var1, memberJwt); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res2.getStatus()); - } - - @Test - public void shouldNotUpdateVariableAsMember() { - final ProjectEnvironment env = new ProjectEnvironment(); - env.setName("test"); - - final Response res1 = envApi.create(project.getId(), env, adminJwt); - final ProjectEnvironment createdEnvironment = res1.readEntity(ProjectEnvironment.class); - - final ProjectEnvironmentVariable var1 = new ProjectEnvironmentVariable(); - var1.setName("var1"); - var1.setValue("test"); - - final Response res2 = envApi.createVariable(project.getId(), createdEnvironment.getId(), var1, adminJwt); - assertEquals(HttpStatus.CREATED.value(), res2.getStatus()); - - final ProjectEnvironmentVariable createdVariable = res2.readEntity(ProjectEnvironmentVariable.class); - createdVariable.setName("tessst"); - - final Response res3 = envApi.updateVariable(project.getId(), createdEnvironment.getId(), createdVariable.getId(), createdVariable, memberJwt); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res3.getStatus()); - } - - @Test - public void shouldNotDeleteVariableAsMember() { - final ProjectEnvironment env = new ProjectEnvironment(); - env.setName("test"); - - final Response res1 = envApi.create(project.getId(), env, adminJwt); - final ProjectEnvironment createdEnvironment = res1.readEntity(ProjectEnvironment.class); - - final ProjectEnvironmentVariable var1 = new ProjectEnvironmentVariable(); - var1.setName("var1"); - var1.setValue("test"); - - final Response res2 = envApi.createVariable(project.getId(), createdEnvironment.getId(), var1, adminJwt); - assertEquals(HttpStatus.CREATED.value(), res2.getStatus()); - - final ProjectEnvironmentVariable createdVariable = res2.readEntity(ProjectEnvironmentVariable.class); - - final Response res3 = envApi.deleteVariable(project.getId(), createdEnvironment.getId(), createdVariable.getId(), memberJwt); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res3.getStatus()); - } - - private void assertVariablesAreTheSame(ProjectEnvironment env1, ProjectEnvironment env2) { - assertEquals(env1.getVariables().size(), env2.getVariables().size()); - for (ProjectEnvironmentVariable v : env1.getVariables()) { - assertEquals(1, env2.getVariables().stream().filter(u -> - u.getName().equals(v.getName()) && u.getValue().equals(v.getValue())).count() - ); - } - } - - private void assertUrlsAreTheSame(ProjectEnvironment env1, ProjectEnvironment env2) { - assertEquals(env1.getUrls().size(), env2.getUrls().size()); - for (ProjectUrl url : env1.getUrls()) { - assertEquals(1, env2.getUrls().stream().filter(u -> - u.getName().equals(url.getName()) && u.getUrl().equals(url.getUrl())).count() - ); - } - } - - private List getAllEnvironments() { - return envApi.getAll(project.getId(), adminJwt) - .readEntity(new GenericType<>() { - }); - } - - private ProjectEnvironment getById(Long envId) { - return getAllEnvironments().stream() - .filter(e -> e.getId().equals(envId)) - .findFirst() - .orElse(null); - } - - private int countEnvironments() { - return getAllEnvironments().size(); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/ProjectResourceIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/ProjectResourceIT.java deleted file mode 100644 index 106e527b3..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/ProjectResourceIT.java +++ /dev/null @@ -1,575 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.jayway.jsonpath.JsonPath; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.integrationtests.SpringRestError; -import de.learnlib.alex.integrationtests.resources.api.ProjectApi; -import de.learnlib.alex.integrationtests.resources.api.SymbolGroupApi; -import de.learnlib.alex.integrationtests.resources.api.UserApi; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import javax.ws.rs.core.GenericType; -import javax.ws.rs.core.Response; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.http.HttpStatus; - -public class ProjectResourceIT extends AbstractResourceIT { - - private String adminJwt; - private User admin; - private String user1Jwt; - private User user1; - private String user2Jwt; - private User user2; - - private UserApi userApi; - private ProjectApi projectApi; - private SymbolGroupApi symbolGroupApi; - - @BeforeEach - public void pre() { - userApi = new UserApi(client, port); - projectApi = new ProjectApi(client, port); - symbolGroupApi = new SymbolGroupApi(client, port); - - userApi.create("{\"email\":\"test@test.de\",\"username\":\"test\",\"password\":\"test\"}"); - userApi.create("{\"email\":\"user2@test.de\",\"username\":\"user2\",\"password\":\"test\"}"); - - adminJwt = userApi.login(ADMIN_EMAIL, ADMIN_PASSWORD); - user1Jwt = userApi.login("test@test.de", "test"); - user2Jwt = userApi.login("user2@test.de", "test"); - - admin = userApi.getProfile(adminJwt).readEntity(User.class); - user1 = userApi.getProfile(user1Jwt).readEntity(User.class); - user2 = userApi.getProfile(user2Jwt).readEntity(User.class); - } - - @Test - public void shouldCreateAProjectWithDefaultEnvironment() { - final String url = "http://localhost:8080/"; - final String project = createProjectJson("test", url); - final Response res = projectApi.create(project, adminJwt); - - assertEquals(HttpStatus.CREATED.value(), res.getStatus()); - - final String body = res.readEntity(String.class); - JsonPath.read(body, "id"); - JsonPath.read(body, "environments[0].id"); - JsonPath.read(body, "environments[0].urls[0].id"); - - final String envName = JsonPath.read(body, "environments[0].name"); - assertEquals("Production", envName); - - final String u = JsonPath.read(body, "environments[0].urls[0].url"); - assertEquals(url, u); - } - - @Test - public void shouldNotCreateAProjectWithoutUrls() { - final String project = createProjectJson("test", ""); - final Response res = projectApi.create(project, adminJwt); - - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - } - - @Test - public void shouldDeleteMultipleProjects() { - final String project1 = createProjectJson("p1", "http://localhost:8080/"); - final String project2 = createProjectJson("p2", "http://localhost:8080/"); - - final Response res1 = projectApi.create(project1, adminJwt); - final Response res2 = projectApi.create(project2, adminJwt); - - final List ids = Stream.of(res1, res2) - .map(res -> res.readEntity(Project.class).getId().toString()) - .collect(Collectors.toList()); - - final Response res3 = projectApi.delete(ids, adminJwt); - assertEquals(HttpStatus.NO_CONTENT.value(), res3.getStatus()); - - final Response res4 = projectApi.getAll(adminJwt); - assertEquals("[]", res4.readEntity(String.class)); - } - - @Test - public void shouldNotCreateAProjectWithAnInvalidUrl() { - final String project = createProjectJson("", "http://localhost:8080/"); - final Response res = projectApi.create(project, adminJwt); - - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - } - - @Test - public void shouldImportProject() throws Exception { - final String path = Thread.currentThread().getContextClassLoader().getResource("integrationtest/ALEX-rest.project.json").getPath(); - final String content = new String(Files.readAllBytes(Paths.get(path))); - - final Response res = projectApi.importProject(content, adminJwt); - assertEquals(HttpStatus.CREATED.value(), res.getStatus()); - } - - @Test - public void shouldNotGetProjectOfAnotherUser() { - final Project project = projectApi.create(createProjectJson("test", "http://localhost:8080/"), adminJwt) - .readEntity(Project.class); - - final Response res2 = projectApi.get(project.getId(), user1Jwt); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res2.getStatus()); - } - - @Test - public void shouldCreateADefaultGroup() { - final String project = - createProjectJson("test", "http://localhost:8080/"); - final Response res = projectApi.create(project, adminJwt); - - final int projectId = JsonPath.read(res.readEntity(String.class), "id"); - - final Response res2 = symbolGroupApi.getAll(projectId, adminJwt); - - final String body = res2.readEntity(String.class); - JsonPath.read(body, "[0].id"); - assertEquals(JsonPath.read(body, "[0].name"), "Default group"); - } - - @Test - public void shouldNotBePossibleToGetANonExistingProject() { - final Response res = projectApi.get(-1L, adminJwt); - assertEquals(HttpStatus.NOT_FOUND.value(), res.getStatus()); - } - - @Test - public void shouldUpdateAProject() throws Exception { - final Project project = createTestProject(adminJwt); - project.setName("updatedTest"); - - final Response res = projectApi.update(project.getId(), objectMapper.writeValueAsString(project), adminJwt); - assertEquals(HttpStatus.OK.value(), res.getStatus()); - - final Project updatedProject = res.readEntity(Project.class); - assertEquals("updatedTest", updatedProject.getName()); - } - - @Test - public void shouldDeleteAProject() throws Exception { - final Project project = createTestProject(adminJwt); - final Response res = projectApi.delete(project.getId(), adminJwt); - - assertEquals(HttpStatus.NO_CONTENT.value(), res.getStatus()); - assertEquals(0, objectMapper.readTree(projectApi.getAll(adminJwt).readEntity(String.class)).size()); - } - - @Test - public void shouldNotDeleteTheProjectOfAnotherUser() { - final Project project = createTestProject(adminJwt); - - final Response res1 = projectApi.delete(project.getId(), user1Jwt); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res1.getStatus()); - - final Response res2 = projectApi.get(project.getId(), adminJwt); - assertEquals(HttpStatus.OK.value(), res2.getStatus()); - res2.readEntity(Project.class); - } - - @Test - public void shouldAddMembers() throws Exception { - final Project project = projectApi.create(createProjectJson("test", "http://localhost:8080/"), adminJwt) - .readEntity(Project.class); - - final Response res = projectApi.addMembers(project.getId(), Arrays.asList(user1.getId(), user2.getId()), adminJwt); - assertEquals(HttpStatus.OK.value(), res.getStatus()); - - final JsonNode updatedProject = objectMapper.readTree(res.readEntity(String.class)); - final List members = Arrays.asList(objectMapper.convertValue(updatedProject.get("members"), Long[].class)); - assertEquals(2, members.size()); - assertTrue(members.contains(user1.getId())); - assertTrue(members.contains(user2.getId())); - } - - @Test - public void shouldAddOwnersAsOwner() throws Exception { - final Project project = projectApi.create(createProjectJson("test", "http://localhost:8080/"), adminJwt) - .readEntity(Project.class); - - final Response res = projectApi.addOwners(project.getId(), Arrays.asList(user1.getId(), user2.getId()), adminJwt); - assertEquals(HttpStatus.OK.value(), res.getStatus()); - - final JsonNode updatedProject = objectMapper.readTree(res.readEntity(String.class)); - final List owners = Arrays.asList(objectMapper.convertValue(updatedProject.get("owners"), Long[].class)); - assertEquals(3, owners.size()); - assertTrue(owners.contains(user1.getId())); - assertTrue(owners.contains(user2.getId())); - } - - @Test - public void shouldPromoteMembersAsOwner() throws Exception { - final Project project = projectApi.create(createProjectJson("test", "http://localhost:8080/"), adminJwt) - .readEntity(Project.class); - - projectApi.addMembers(project.getId(), Arrays.asList(user1.getId(), user2.getId()), adminJwt); - - final Response res1 = projectApi.addOwners(project.getId(), Arrays.asList(user1.getId(), user2.getId()), adminJwt); - assertEquals(HttpStatus.OK.value(), res1.getStatus()); - - final JsonNode updatedProject = objectMapper.readTree(res1.readEntity(String.class)); - final List ownerIds = Arrays.asList(objectMapper.convertValue(updatedProject.get("owners"), Long[].class)); - final List memberIds = Arrays.asList(objectMapper.convertValue(updatedProject.get("members"), Long[].class)); - - assertEquals(0, memberIds.size()); - assertEquals(3, ownerIds.size()); - assertTrue(ownerIds.contains(user1.getId())); - assertTrue(ownerIds.contains(user2.getId())); - } - - @Test - public void shouldDemoteOwnersAsOwner() throws Exception { - final Project project = projectApi.create(createProjectJson("test", "http://localhost:8080/"), adminJwt) - .readEntity(Project.class); - - projectApi.addOwners(project.getId(), Arrays.asList(user1.getId(), user2.getId()), adminJwt); - - final Response res1 = projectApi.addMembers(project.getId(), Arrays.asList(user1.getId(), user2.getId()), adminJwt); - assertEquals(HttpStatus.OK.value(), res1.getStatus()); - - final JsonNode updatedProject = objectMapper.readTree(res1.readEntity(String.class)); - final List ownerIds = Arrays.asList(objectMapper.convertValue(updatedProject.get("owners"), Long[].class)); - final List memberIds = Arrays.asList(objectMapper.convertValue(updatedProject.get("members"), Long[].class)); - - assertEquals(2, memberIds.size()); - assertTrue(memberIds.contains(user1.getId())); - assertTrue(memberIds.contains(user2.getId())); - - assertEquals(1, ownerIds.size()); - assertFalse(ownerIds.contains(user1.getId())); - assertFalse(ownerIds.contains(user2.getId())); - } - - @Test - public void shouldRemoveMembers() throws Exception { - final Project project = projectApi.create(createProjectJson("test", "http://localhost:8080/"), adminJwt) - .readEntity(Project.class); - - projectApi.addMembers(project.getId(), Arrays.asList(user1.getId(), user2.getId()), adminJwt); - - final Response res1 = projectApi.removeMembers(project.getId(), Arrays.asList(user1.getId(), user2.getId()), adminJwt); - assertEquals(HttpStatus.OK.value(), res1.getStatus()); - - final JsonNode updatedProject = objectMapper.readTree( - projectApi.get(project.getId(), adminJwt).readEntity(String.class) - ); - - final List ownerIds = Arrays.asList( - objectMapper.readValue(updatedProject.get("owners").toString(), Long[].class) - ); - - assertEquals(1, ownerIds.size()); - assertFalse(ownerIds.contains(user1.getId())); - assertFalse(ownerIds.contains(user2.getId())); - } - - @Test - public void shouldRemoveOwnersAsOwner() throws Exception { - final Project project = projectApi.create(createProjectJson("test", "http://localhost:8080/"), adminJwt) - .readEntity(Project.class); - - projectApi.addOwners(project.getId(), Arrays.asList(user1.getId(), user2.getId()), adminJwt); - - final Response res1 = projectApi.removeOwners(project.getId(), Arrays.asList(user1.getId(), user2.getId()), adminJwt); - assertEquals(HttpStatus.OK.value(), res1.getStatus()); - - final JsonNode updatedProject = objectMapper.readTree( - projectApi.get(project.getId(), adminJwt).readEntity(String.class) - ); - - final List ownerIds = Arrays.asList( - objectMapper.readValue(updatedProject.get("owners").toString(), Long[].class) - ); - - assertEquals(1, ownerIds.size()); - assertFalse(ownerIds.contains(user1.getId())); - assertFalse(ownerIds.contains(user2.getId())); - } - - @Test - public void shouldNotAllowMembersToUpdateTheProject() throws Exception { - Project project = projectApi.create(createProjectJson("test", "http://localhost:8080/"), adminJwt) - .readEntity(Project.class); - - projectApi.addMembers(project.getId(), Collections.singletonList(user1.getId()), adminJwt); - - project.setName("updatedTest"); - - final Response res1 = projectApi.update(project.getId(), objectMapper.writeValueAsString(project), user1Jwt); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res1.getStatus()); - - project = projectApi.get(project.getId(), adminJwt).readEntity(Project.class); - assertEquals("test", project.getName()); - } - - @Test - public void shouldNotRemoveLastOwner() throws IOException { - final Project project = projectApi.create(createProjectJson("test", "http://localhost:8080/"), adminJwt) - .readEntity(Project.class); - - projectApi.addOwners(project.getId(), Collections.singletonList(user1.getId()), adminJwt); - - final Response res = projectApi.removeOwners(project.getId(), Arrays.asList(admin.getId(), user1.getId()), adminJwt); - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - - final JsonNode projectJson = objectMapper.readTree( - projectApi.get(project.getId(), adminJwt).readEntity(String.class) - ); - - assertEquals(0, projectJson.get("members").size()); - assertEquals(2, projectJson.get("owners").size()); - } - - @Test - public void shouldCrudProject() throws Exception { - final Response res1 = projectApi.create(createProjectJson("test", "http://localhost:8080/"), adminJwt); - final Project project = res1.readEntity(Project.class); - - assertEquals(HttpStatus.CREATED.value(), res1.getStatus()); - - final Response res2 = projectApi.get(project.getId(), adminJwt); - assertEquals(HttpStatus.OK.value(), res2.getStatus()); - - project.setName("updatedName"); - final Response res3 = projectApi.update(project.getId(), objectMapper.writeValueAsString(project), adminJwt); - assertEquals(HttpStatus.OK.value(), res3.getStatus()); - - final Response res4 = projectApi.delete(project.getId(), adminJwt); - assertEquals(HttpStatus.NO_CONTENT.value(), res4.getStatus()); - - final Response res5 = projectApi.get(project.getId(), adminJwt); - assertEquals(HttpStatus.NOT_FOUND.value(), res5.getStatus()); - } - - @Test - public void shouldCreateProjectWithAlreadyExistingName() throws IOException { - final Response res1 = - projectApi.create(createProjectJson("test", "http://localhost:8080/"), adminJwt); - assertEquals(HttpStatus.CREATED.value(), res1.getStatus()); - - final JsonNode project1 = objectMapper.readTree(res1.readEntity(String.class)); - final int projectId1 = project1.get("id").asInt(); - - final Response res2 = - projectApi.create(createProjectJson("test", "http://localhost:8080/"), adminJwt); - assertEquals(HttpStatus.CREATED.value(), res2.getStatus()); - - final JsonNode project2 = objectMapper.readTree(res2.readEntity(String.class)); - final int projectId2 = project2.get("id").asInt(); - - final Response res3 = - projectApi.getAll(adminJwt); - final String body = res3.readEntity(String.class); - List projectIds = new ArrayList<>(); - projectIds.add(JsonPath.read(body, "[0].id")); - projectIds.add(JsonPath.read(body, "[1].id")); - assertTrue(projectIds.contains(projectId1)); - assertTrue(projectIds.contains(projectId2)); - } - - @Test - public void shouldUpdateProjectNameToAlreadyExistingName() throws IOException { - final Response res1 = - projectApi.create(createProjectJson("test", "http://localhost:8080/"), adminJwt); - assertEquals(HttpStatus.CREATED.value(), res1.getStatus()); - - final JsonNode project1 = objectMapper.readTree(res1.readEntity(String.class)); - final Long projectId1 = project1.get("id").asLong(); - - final Response res2 = - projectApi.create(createProjectJson("test2", "http://localhost:8080/"), adminJwt); - assertEquals(HttpStatus.CREATED.value(), res2.getStatus()); - - final JsonNode project2 = objectMapper.readTree(res2.readEntity(String.class)); - final Long projectId2 = project2.get("id").asLong(); - - ((ObjectNode) project2).put("name", "test"); - - final Response res3 = projectApi.update(projectId2, project2.toString(), adminJwt); - assertEquals(HttpStatus.OK.value(), res3.getStatus()); - - final List projectIds = projectApi.getAll(adminJwt) - .readEntity(new GenericType>() { - }) - .stream() - .map(Project::getId) - .collect(Collectors.toList()); - - assertTrue(projectIds.contains(projectId1)); - assertTrue(projectIds.contains(projectId2)); - } - - @Test - public void shouldGetCorrectlyAddedToProjectWithSameName() throws IOException { - final Response res1 = projectApi.create(createProjectJson("test", "http://localhost:8080/"), adminJwt); - assertEquals(HttpStatus.CREATED.value(), res1.getStatus()); - - final Project project1 = res1.readEntity(Project.class); - - final Response res2 = projectApi.create(createProjectJson("test2", "http://localhost:8080/"), user1Jwt); - assertEquals(HttpStatus.CREATED.value(), res2.getStatus()); - - final Project project2 = res2.readEntity(Project.class); - - final Response res3 = projectApi.addOwners(project1.getId(), Collections.singletonList(user1.getId()), adminJwt); - assertEquals(HttpStatus.OK.value(), res3.getStatus()); - - final List projectIds = projectApi.getAll(user1Jwt) - .readEntity(new GenericType>() { - }) - .stream() - .map(Project::getId) - .collect(Collectors.toList()); - - assertTrue(projectIds.contains(project1.getId())); - assertTrue(projectIds.contains(project2.getId())); - } - - @Test - public void memberShouldNotDeleteProject() { - Project project = createTestProject(adminJwt); - - project = projectApi.addMembers(project.getId(), Collections.singletonList(user1.getId()), adminJwt) - .readEntity(Project.class); - - final Response res = projectApi.delete(project.getId(), user1Jwt); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res.getStatus()); - res.readEntity(SpringRestError.class); - - final Response res2 = projectApi.get(project.getId(), adminJwt); - assertEquals(HttpStatus.OK.value(), res2.getStatus()); - res2.readEntity(Project.class); - } - - @Test - public void memberShouldNotPromoteHimself() throws IOException { - Project project = createTestProject(adminJwt); - - project = projectApi.addMembers(project.getId(), Collections.singletonList(user1.getId()), adminJwt) - .readEntity(Project.class); - - final Response res1 = projectApi.addOwners(project.getId(), Collections.singletonList(user1.getId()), user1Jwt); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res1.getStatus()); - res1.readEntity(SpringRestError.class); - - final JsonNode project2 = objectMapper.readTree( - projectApi.get(project.getId(), adminJwt).readEntity(String.class) - ); - - assertEquals(1, project2.get("members").size()); - assertEquals((long) user1.getId(), project2.get("members").get(0).asLong()); - assertEquals(1, project2.get("owners").size()); - assertEquals((long) admin.getId(), project2.get("owners").get(0).asLong()); - } - - @Test - public void memberShouldNotDemoteOwner() throws IOException { - Project project = createTestProject(adminJwt); - - project = projectApi.addMembers(project.getId(), Collections.singletonList(user1.getId()), adminJwt) - .readEntity(Project.class); - - final Response res1 = projectApi.removeOwners(project.getId(), Collections.singletonList(admin.getId()), user1Jwt); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res1.getStatus()); - res1.readEntity(SpringRestError.class); - - final JsonNode project2 = objectMapper.readTree( - projectApi.get(project.getId(), adminJwt).readEntity(String.class) - ); - - assertEquals(1, project2.get("members").size()); - assertEquals((long) user1.getId(), project2.get("members").get(0).asLong()); - assertEquals(1, project2.get("owners").size()); - assertEquals((long) admin.getId(), project2.get("owners").get(0).asLong()); - } - - @Test - public void memberShouldNotRemoveOtherMember() throws IOException { - Project project = createTestProject(adminJwt); - - project = projectApi.addMembers(project.getId(), Collections.singletonList(user1.getId()), adminJwt) - .readEntity(Project.class); - project = projectApi.addMembers(project.getId(), Collections.singletonList(user2.getId()), adminJwt) - .readEntity(Project.class); - - final Response res1 = projectApi.removeMembers(project.getId(), Collections.singletonList(user2.getId()), user1Jwt); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res1.getStatus()); - res1.readEntity(SpringRestError.class); - - final JsonNode project2 = objectMapper.readTree( - projectApi.get(project.getId(), adminJwt).readEntity(String.class) - ); - - final List memberIds = Arrays.asList(objectMapper.readValue(project2.get("members").toString(), Long[].class)); - assertEquals(2, memberIds.size()); - assertTrue(memberIds.contains(user1.getId())); - assertTrue(memberIds.contains(user2.getId())); - } - - @Test - public void memberShouldNotRemoveOtherOwner() throws IOException { - Project project = createTestProject(adminJwt); - - project = projectApi.addMembers(project.getId(), Collections.singletonList(user1.getId()), adminJwt) - .readEntity(Project.class); - - final Response res1 = projectApi.removeOwners(project.getId(), Collections.singletonList(admin.getId()), user1Jwt); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res1.getStatus()); - res1.readEntity(SpringRestError.class); - - final JsonNode project2 = objectMapper.readTree( - projectApi.get(project.getId(), adminJwt).readEntity(String.class) - ); - - final List ownerIds = Arrays.asList(objectMapper.readValue(project2.get("owners").toString(), Long[].class)); - assertEquals(1, ownerIds.size()); - assertTrue(ownerIds.contains(admin.getId())); - } - - private Project createTestProject(String jwt) { - return projectApi.create(createProjectJson("test", "http://localhost:8080/"), jwt) - .readEntity(Project.class); - } - - private String createProjectJson(String name, String url) { - return "{" - + "\"name\":\"" + name + "\"" - + ",\"url\":\"" + url + "\"" - + "}"; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/SettingsResourceIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/SettingsResourceIT.java deleted file mode 100644 index b4102c2d3..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/SettingsResourceIT.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import de.learnlib.alex.integrationtests.resources.api.SettingsApi; -import de.learnlib.alex.integrationtests.resources.api.UserApi; -import de.learnlib.alex.settings.entities.Settings; -import javax.ws.rs.core.Response; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.skyscreamer.jsonassert.JSONAssert; -import org.springframework.http.HttpStatus; - -public class SettingsResourceIT extends AbstractResourceIT { - - private SettingsApi settingsApi; - - private String adminJwt; - private String userJwt; - - @BeforeEach - public void pre() { - this.settingsApi = new SettingsApi(client, port); - - final UserApi userApi = new UserApi(client, port); - userApi.create("{\"email\":\"test@test.de\",\"username\":\"test\",\"password\":\"test\"}"); - - adminJwt = userApi.login("admin@alex.example", "admin"); - userJwt = userApi.login("test@test.de", "test"); - } - - @Test - public void anonymousUserShouldGetSettings() throws Exception { - shouldGetSettings(null); - } - - @Test - public void registeredUserShouldGetSettings() throws Exception { - shouldGetSettings(userJwt); - } - - @Test - public void adminShouldGetSettings() throws Exception { - shouldGetSettings(adminJwt); - } - - @Test - public void anonymousUserShouldNotUpdateSettings() throws Exception { - shouldNotUpdateSettings(null); - } - - @Test - public void registeredUserShouldNotUpdateSettings() throws Exception { - shouldNotUpdateSettings(userJwt); - } - - @Test - public void adminShouldUpdateSettings() throws Exception { - final Response res = settingsApi.get(); - final Settings settings = res.readEntity(Settings.class); - - settings.setAllowUserRegistration(false); - - final Response res2 = settingsApi.update(settings, adminJwt); - assertEquals(HttpStatus.OK.value(), res2.getStatus()); - JSONAssert.assertEquals(objectMapper.writeValueAsString(settings), res2.readEntity(String.class), true); - - final Response res3 = settingsApi.get(); - JSONAssert.assertEquals(objectMapper.writeValueAsString(settings), res3.readEntity(String.class), true); - } - - private void shouldNotUpdateSettings(String jwt) throws Exception { - final Response res = settingsApi.get(); - final String settingsString = res.readEntity(String.class); - final Settings settings = objectMapper.readValue(settingsString, Settings.class); - - settings.setAllowUserRegistration(!settings.isAllowUserRegistration()); - - final Response res2 = jwt == null ? settingsApi.update(settings) : settingsApi.update(settings, jwt); - assertEquals(HttpStatus.FORBIDDEN.value(), res2.getStatus()); - - // settings unchanged? - final Response res3 = settingsApi.get(); - JSONAssert.assertEquals(res3.readEntity(String.class), settingsString, true); - } - - private void shouldGetSettings(String jwt) throws Exception { - final Response res; - if (jwt == null) { - res = settingsApi.get(); - } else { - res = settingsApi.get(jwt); - } - assertEquals(HttpStatus.OK.value(), res.getStatus()); - checkIsSettingsObject(res.readEntity(String.class)); - } - - private void checkIsSettingsObject(String body) throws Exception { - objectMapper.readValue(body, Settings.class); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/SymbolGroupResourceIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/SymbolGroupResourceIT.java deleted file mode 100644 index b57c2bce7..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/SymbolGroupResourceIT.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.jayway.jsonpath.JsonPath; -import de.learnlib.alex.data.entities.SymbolGroup; -import de.learnlib.alex.integrationtests.resources.api.ProjectApi; -import de.learnlib.alex.integrationtests.resources.api.SymbolGroupApi; -import de.learnlib.alex.integrationtests.resources.api.UserApi; -import java.util.Arrays; -import java.util.List; -import javax.ws.rs.core.GenericType; -import javax.ws.rs.core.Response; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.http.HttpStatus; - -public class SymbolGroupResourceIT extends AbstractResourceIT { - - private String jwtUser1; - - private String jwtUser2; - - private int projectId1; - - private int projectId2; - - private SymbolGroupApi symbolGroupApi; - - @BeforeEach - public void pre() { - final UserApi userApi = new UserApi(client, port); - ProjectApi projectApi = new ProjectApi(client, port); - symbolGroupApi = new SymbolGroupApi(client, port); - - userApi.create("{\"email\":\"test1@test.de\",\"username\":\"test1\",\"password\":\"test\"}"); - userApi.create("{\"email\":\"test2@test.de\",\"username\":\"test2\",\"password\":\"test\"}"); - - jwtUser1 = userApi.login("test1@test.de", "test"); - jwtUser2 = userApi.login("test2@test.de", "test"); - - final Response res1 = - projectApi.create("{\"name\":\"test\",\"url\":\"http://localhost:8080/"}", jwtUser1); - final Response res2 = - projectApi.create("{\"name\":\"test\",\"url\":\"http://localhost:8080/"}", jwtUser2); - - projectId1 = JsonPath.read(res1.readEntity(String.class), "id"); - projectId2 = JsonPath.read(res2.readEntity(String.class), "id"); - } - - @Test - public void shouldHaveCreatedADefaultGroup() throws Exception { - assertEquals(1, getNumberOfGroups(projectId1, jwtUser1)); - - final Response res = symbolGroupApi.getAll(projectId1, jwtUser1); - final String name = JsonPath.read(res.readEntity(String.class), "[0].name"); - assertEquals(HttpStatus.OK.value(), res.getStatus()); - assertEquals("Default group", name); - } - - @Test - public void shouldCreateAGroup() throws Exception { - final String group = createSymbolGroupJson(projectId1, "group", null); - final Response res = symbolGroupApi.create(projectId1, group, jwtUser1); - assertEquals(HttpStatus.CREATED.value(), res.getStatus()); - assertEquals(2, getNumberOfGroups(projectId1, jwtUser1)); - JsonPath.read(res.readEntity(String.class), "id"); - } - - @Test - public void createAGroupWithAParent() throws Exception { - SymbolGroup parent = new SymbolGroup(); - parent.setName("parent"); - - parent = symbolGroupApi.create(projectId1, objectMapper.writeValueAsString(parent), jwtUser1) - .readEntity(SymbolGroup.class); - - SymbolGroup child = new SymbolGroup(); - child.setName("child"); - child.setParent(parent); - - final Response res = symbolGroupApi.create(projectId1, objectMapper.writeValueAsString(child), jwtUser1); - child = res.readEntity(SymbolGroup.class); - - assertEquals(HttpStatus.CREATED.value(), res.getStatus()); - assertEquals(parent.getId(), child.getParent().getId()); - } - - @Test - public void shouldFailToCreateAGroupIfNameIsEmpty() throws Exception { - final String group2 = createSymbolGroupJson(projectId1, "", null); - final Response res2 = symbolGroupApi.create(projectId1, group2, jwtUser1); - assertEquals(HttpStatus.BAD_REQUEST.value(), res2.getStatus()); - assertEquals(1, getNumberOfGroups(projectId1, jwtUser1)); - } - - @Test - public void shouldIncrementTheNameIfGroupNameExists() { - final String group = createSymbolGroupJson(projectId1, "group", null); - symbolGroupApi.create(projectId1, group, jwtUser1); - final Response res = symbolGroupApi.create(projectId1, group, jwtUser1); - assertEquals(HttpStatus.CREATED.value(), res.getStatus()); - final String name = JsonPath.read(res.readEntity(String.class), "name"); - assertEquals(name, "group (1)"); - } - - @Test - public void shouldNotCreateAGroupInAnotherUsersProject() throws Exception { - final String group = createSymbolGroupJson(projectId2, "group", null); - final Response res = symbolGroupApi.create(projectId2, group, jwtUser1); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res.getStatus()); - assertEquals(1, getNumberOfGroups(projectId1, jwtUser1)); - assertEquals(1, getNumberOfGroups(projectId2, jwtUser2)); - } - - @Test - public void shouldMoveGroup() throws Exception { - final String defaultGroup = getDefaultGroupJson(projectId1, jwtUser1); - final int defaultGroupId = JsonPath.read(defaultGroup, "id"); - - final String group = createSymbolGroupJson(projectId1, "childGroup", null); - final Response res1 = symbolGroupApi.create(projectId1, group, jwtUser1); - final int groupId = JsonPath.read(res1.readEntity(String.class), "id"); - - final String updatedGroup = ((ObjectNode) objectMapper.readTree(group)) - .put("id", groupId) - .put("parent", defaultGroupId) - .toString(); - - final Response res2 = symbolGroupApi.move(projectId1, groupId, updatedGroup, jwtUser1); - assertEquals(HttpStatus.OK.value(), res2.getStatus()); - assertEquals(1, getNumberOfGroups(projectId1, jwtUser1)); - - final Response res3 = symbolGroupApi.getAll(projectId1, jwtUser1); - final int id = JsonPath.read(res3.readEntity(String.class), "[0].groups[0].id"); - assertEquals(groupId, id); - } - - @Test - public void shouldUpdateGroup() throws Exception { - final String group = createSymbolGroupJson(projectId1, "group", null); - final Response res1 = symbolGroupApi.create(projectId1, group, jwtUser1); - final SymbolGroup createdGroup = res1.readEntity(SymbolGroup.class); - - createdGroup.setName("anotherName"); - - final Response res = symbolGroupApi.update(projectId1, createdGroup.getId().intValue(), objectMapper.writeValueAsString(createdGroup), jwtUser1); - assertEquals(HttpStatus.OK.value(), res.getStatus()); - - final SymbolGroup updatedGroup = res.readEntity(SymbolGroup.class); - assertEquals(createdGroup.getId(), updatedGroup.getId()); - assertEquals("anotherName", updatedGroup.getName()); - } - - @Test - public void shouldNotMoveDefaultGroup() throws Exception { - final String defaultGroupPre = getDefaultGroupJson(projectId1, jwtUser1); - final int defaultGroupId = JsonPath.read(defaultGroupPre, "id"); - - final String group = createSymbolGroupJson(projectId1, "group", null); - final Response res1 = symbolGroupApi.create(projectId1, group, jwtUser1); - final int parentId = JsonPath.read(res1.readEntity(String.class), "id"); - - final JsonNode defaultGroupNode = objectMapper.readTree(defaultGroupPre); - ((ObjectNode) defaultGroupNode).put("parent", parentId); - - final Response res2 = symbolGroupApi.move(projectId1, defaultGroupId, defaultGroupNode.toString(), jwtUser1); - assertEquals(HttpStatus.BAD_REQUEST.value(), res2.getStatus()); - - final String defaultGroupPost = getDefaultGroupJson(projectId1, jwtUser1); - assertFalse(objectMapper.readTree(defaultGroupPost).has("parent")); - } - - @Test - public void shouldDeleteAGroup() throws Exception { - final String group = createSymbolGroupJson(projectId1, "group", null); - final Response res1 = symbolGroupApi.create(projectId1, group, jwtUser1); - final int groupId = JsonPath.read(res1.readEntity(String.class), "id"); - - final Response res2 = symbolGroupApi.delete(projectId1, groupId, jwtUser1); - assertEquals(HttpStatus.NO_CONTENT.value(), res2.getStatus()); - assertEquals(1, getNumberOfGroups(projectId1, jwtUser1)); - } - - @Test - public void shouldNotDeleteTheDefaultGroup() throws Exception { - final String group = getDefaultGroupJson(projectId1, jwtUser1); - final int groupId = JsonPath.read(group, "id"); - - final Response res = symbolGroupApi.delete(projectId1, groupId, jwtUser1); - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - assertEquals(1, getNumberOfGroups(projectId1, jwtUser1)); - } - - @Test - public void shouldNotDeleteAGroupOfAnotherUser() throws Exception { - final String group = createSymbolGroupJson(projectId1, "group", null); - final Response res1 = symbolGroupApi.create(projectId2, group, jwtUser2); - final int groupId = JsonPath.read(res1.readEntity(String.class), "id"); - - final Response res2 = symbolGroupApi.delete(projectId2, groupId, jwtUser1); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res2.getStatus()); - assertEquals(2, getNumberOfGroups(projectId2, jwtUser2)); - assertEquals(1, getNumberOfGroups(projectId1, jwtUser1)); - - final Response res3 = symbolGroupApi.delete(projectId1, groupId, jwtUser1); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res3.getStatus()); - assertEquals(2, getNumberOfGroups(projectId2, jwtUser2)); - assertEquals(1, getNumberOfGroups(projectId1, jwtUser1)); - } - - @Test - public void shouldGetAGroupById() { - final String group = createSymbolGroupJson(projectId1, "group", null); - final Response res1 = symbolGroupApi.create(projectId1, group, jwtUser1); - final SymbolGroup g = res1.readEntity(SymbolGroup.class); - - final Response res2 = symbolGroupApi.get(g.getProjectId(), g.getId(), jwtUser1); - final SymbolGroup g2 = res2.readEntity(SymbolGroup.class); - - assertEquals(g.getId(), g2.getId()); - } - - @Test - public void shouldCreateMultipleGroupsAtOnce() { - final SymbolGroup g1 = new SymbolGroup(); - g1.setName("group1"); - - final SymbolGroup g2 = new SymbolGroup(); - g2.setName("group2"); - - final Response res = symbolGroupApi.create(projectId1, Arrays.asList(g1, g2), jwtUser1); - final List createdGroups = res.readEntity(new GenericType<>() { - }); - - assertEquals(2, createdGroups.size()); - assertEquals("group1", createdGroups.get(0).getName()); - assertEquals("group2", createdGroups.get(1).getName()); - - final Response res1 = symbolGroupApi.getAll(projectId1, jwtUser1); - final List allGroups = res1.readEntity(new GenericType<>() { - }); - assertTrue(allGroups.containsAll(createdGroups)); - } - - private String getDefaultGroupJson(int projectId, String jwt) throws Exception { - final Response res = symbolGroupApi.getAll(projectId, jwt); - return objectMapper.readTree(res.readEntity(String.class)).get(0).toString(); - } - - private int getNumberOfGroups(int projectId, String jwt) throws Exception { - final Response res = symbolGroupApi.getAll(projectId, jwt); - return objectMapper.readTree(res.readEntity(String.class)).size(); - } - - private String createSymbolGroupJson(int projectId, String name, Integer parentId) { - return "{" - + "\"name\":\"" + name + "\"" - + ",\"parent\":" + parentId - + ",\"project\":" + projectId - + ",\"symbols\":[]" - + ",\"groups\":[]" - + "}"; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/SymbolParameterResourceIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/SymbolParameterResourceIT.java deleted file mode 100644 index fa0fba041..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/SymbolParameterResourceIT.java +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.jayway.jsonpath.JsonPath; -import de.learnlib.alex.integrationtests.resources.api.ProjectApi; -import de.learnlib.alex.integrationtests.resources.api.SymbolApi; -import de.learnlib.alex.integrationtests.resources.api.SymbolParameterApi; -import de.learnlib.alex.integrationtests.resources.api.UserApi; -import de.learnlib.alex.integrationtests.websocket.util.SymbolPresenceServiceWSMessages; -import de.learnlib.alex.integrationtests.websocket.util.WebSocketUser; -import java.time.Duration; -import java.util.Collections; -import java.util.List; -import javax.ws.rs.core.Response; -import org.awaitility.Awaitility; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.skyscreamer.jsonassert.JSONAssert; - -public class SymbolParameterResourceIT extends AbstractResourceIT { - - private final Duration defaultWaitTime = Duration.ofSeconds(5); - private final ObjectMapper om = new ObjectMapper(); - - private SymbolParameterApi symbolParameterApi; - - private SymbolApi symbolApi; - - private String jwtUser1; - - private int projectId; - - private int symbolId; - - private SymbolPresenceServiceWSMessages symbolPresenceServiceWSMessages; - - private ProjectApi projectApi; - - @BeforeEach - public void pre() { - this.symbolParameterApi = new SymbolParameterApi(client, port); - this.symbolPresenceServiceWSMessages = new SymbolPresenceServiceWSMessages(); - - final UserApi userApi = new UserApi(client, port); - userApi.create("{\"email\":\"test1@test.de\",\"username\":\"test1\",\"password\":\"test\"}"); - jwtUser1 = userApi.login("test1@test.de", "test"); - - projectApi = new ProjectApi(client, port); - final Response res1 = projectApi.create("{\"name\":\"test\",\"url\":\"http://test/"}", jwtUser1); - assertEquals(res1.getStatus(), Response.Status.CREATED.getStatusCode()); - this.projectId = JsonPath.read(res1.readEntity(String.class), "$.id"); - - this.symbolApi = new SymbolApi(client, port); - final Response res2 = symbolApi.create(projectId, "{\"name\":\"s1\",\"steps\":[]}", jwtUser1); - assertEquals(res2.getStatus(), Response.Status.CREATED.getStatusCode()); - this.symbolId = JsonPath.read(res2.readEntity(String.class), "$.id"); - } - - @Test - public void shouldCreateAnInputStringParameter() throws Exception { - final Response res = symbolParameterApi.create(projectId, symbolId, createInputStringParam(symbolId, "test"), jwtUser1); - assertEquals(res.getStatus(), Response.Status.CREATED.getStatusCode()); - - final JsonNode symbol = getSymbol(); - final JsonNode inputs = symbol.get("inputs"); - - assertEquals(1, inputs.size()); - assertTrue(inputs.get(0).hasNonNull("id")); - assertEquals("STRING", inputs.get(0).get("parameterType").asText()); - } - - @Test - public void shouldCreateAnInputCounterParameter() throws Exception { - final Response res = symbolParameterApi.create(projectId, symbolId, createInputCounterParam(symbolId, "test"), jwtUser1); - assertEquals(res.getStatus(), Response.Status.CREATED.getStatusCode()); - - final JsonNode symbol = getSymbol(); - final JsonNode inputs = symbol.get("inputs"); - - assertEquals(1, inputs.size()); - assertTrue(inputs.get(0).hasNonNull("id")); - assertEquals("COUNTER", inputs.get(0).get("parameterType").asText()); - } - - @Test - public void shouldCreateAnOutputStringParameter() throws Exception { - final Response res = symbolParameterApi.create(projectId, symbolId, createOutputStringParam(symbolId, "test"), jwtUser1); - assertEquals(res.getStatus(), Response.Status.CREATED.getStatusCode()); - - final JsonNode symbol = getSymbol(); - final JsonNode inputs = symbol.get("outputs"); - - assertEquals(1, inputs.size()); - assertTrue(inputs.get(0).hasNonNull("id")); - assertEquals("STRING", inputs.get(0).get("parameterType").asText()); - } - - @Test - public void shouldCreateAnOutputCounterParameter() throws Exception { - final Response res = symbolParameterApi.create(projectId, symbolId, createOutputCounterParam(symbolId, "test"), jwtUser1); - assertEquals(res.getStatus(), Response.Status.CREATED.getStatusCode()); - - final JsonNode symbol = getSymbol(); - final JsonNode inputs = symbol.get("outputs"); - - assertEquals(1, inputs.size()); - assertTrue(inputs.get(0).hasNonNull("id")); - assertEquals("COUNTER", inputs.get(0).get("parameterType").asText()); - } - - @Test - public void shouldNotCreateInputParameterIfNameIsTaken() throws Exception { - symbolParameterApi.create(projectId, symbolId, createInputStringParam(symbolId, "test"), jwtUser1); - final Response res1 = symbolParameterApi.create(projectId, symbolId, createInputStringParam(symbolId, "test"), jwtUser1); - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), res1.getStatus()); - - final Response res2 = symbolParameterApi.create(projectId, symbolId, createInputCounterParam(symbolId, "test"), jwtUser1); - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), res2.getStatus()); - - final JsonNode symbol = getSymbol(); - assertEquals(1, symbol.get("inputs").size()); - } - - @Test - public void shouldNotCreateOutputParameterIfNameIsTaken() throws Exception { - symbolParameterApi.create(projectId, symbolId, createOutputStringParam(symbolId, "test"), jwtUser1); - final Response res1 = symbolParameterApi.create(projectId, symbolId, createOutputStringParam(symbolId, "test"), jwtUser1); - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), res1.getStatus()); - - final Response res2 = symbolParameterApi.create(projectId, symbolId, createOutputCounterParam(symbolId, "test"), jwtUser1); - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), res2.getStatus()); - - final JsonNode symbol = getSymbol(); - assertEquals(1, symbol.get("outputs").size()); - } - - @Test - public void shouldCreateParameterOnSymbolLockedByUser() throws Exception { - WebSocketUser webSocketUser = new WebSocketUser("webSocketUser", client, port); - projectApi.addMembers(Integer.toUnsignedLong(projectId), Collections.singletonList(webSocketUser.getUserId()), jwtUser1); - - webSocketUser.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId, symbolId)); - Awaitility.await().atMost(defaultWaitTime).until(() -> webSocketUser.assertNumberOfMessages(List.of("default"), List.of(1))); - - final Response res = symbolParameterApi.create(projectId, symbolId, createInputStringParam(symbolId, "test"), webSocketUser.getJwt()); - assertEquals(res.getStatus(), Response.Status.CREATED.getStatusCode()); - - webSocketUser.forceDisconnectAll(); - } - - @Test - public void shouldNotCreateParameterOnSymbolLockedByOtherUser() throws Exception { - WebSocketUser webSocketUser = new WebSocketUser("webSocketUser", client, port); - projectApi.addMembers(Integer.toUnsignedLong(projectId), Collections.singletonList(webSocketUser.getUserId()), jwtUser1); - - webSocketUser.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId, symbolId)); - Awaitility.await().atMost(defaultWaitTime).until(() -> webSocketUser.assertNumberOfMessages(List.of("default"), List.of(1))); - - final Response res = symbolParameterApi.create(projectId, symbolId, createInputStringParam(symbolId, "test"), jwtUser1); - assertEquals(res.getStatus(), Response.Status.UNAUTHORIZED.getStatusCode()); - - webSocketUser.forceDisconnectAll(); - } - - @Test - public void shouldUpdateInputParameter() throws Exception { - final Response res1 = symbolParameterApi.create(projectId, symbolId, createInputStringParam(symbolId, "test"), jwtUser1); - final JsonNode paramNode = objectMapper.readTree(res1.readEntity(String.class)); - - ((ObjectNode) paramNode).put("name", "newName"); - - final Response res2 = symbolParameterApi.update(projectId, symbolId, paramNode.get("id").asInt(), paramNode.toString(), jwtUser1); - assertEquals(Response.Status.OK.getStatusCode(), res2.getStatus()); - assertEquals(paramNode.toString(), res2.readEntity(String.class)); - } - - @Test - public void shouldUpdateOutputParameter() throws Exception { - final Response res1 = symbolParameterApi.create(projectId, symbolId, createOutputStringParam(symbolId, "test"), jwtUser1); - final JsonNode paramNode = objectMapper.readTree(res1.readEntity(String.class)); - - ((ObjectNode) paramNode).put("name", "newName"); - - final Response res2 = symbolParameterApi.update(projectId, symbolId, paramNode.get("id").asInt(), paramNode.toString(), jwtUser1); - assertEquals(Response.Status.OK.getStatusCode(), res2.getStatus()); - assertEquals(paramNode.toString(), res2.readEntity(String.class)); - } - - @Test - public void shouldNotUpdateInputParameterIfNameIsTaken() throws Exception { - symbolParameterApi.create(projectId, symbolId, createInputStringParam(symbolId, "test"), jwtUser1); - final Response res1 = symbolParameterApi.create(projectId, symbolId, createInputStringParam(symbolId, "test2"), jwtUser1); - final JsonNode paramNode = objectMapper.readTree(res1.readEntity(String.class)); - ((ObjectNode) paramNode).put("name", "test"); - - final String symbolPre = symbolApi.getAll(projectId, jwtUser1).readEntity(String.class); - - final Response res2 = symbolParameterApi.update(projectId, symbolId, paramNode.get("id").asInt(), paramNode.toString(), jwtUser1); - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), res2.getStatus()); - - final String symbolPost = symbolApi.getAll(projectId, jwtUser1).readEntity(String.class); - JSONAssert.assertEquals(symbolPre, symbolPost, true); - } - - @Test - public void shouldNotUpdateOutputParameterIfNameIsTaken() throws Exception { - symbolParameterApi.create(projectId, symbolId, createOutputStringParam(symbolId, "test"), jwtUser1); - final Response res1 = symbolParameterApi.create(projectId, symbolId, createOutputStringParam(symbolId, "test2"), jwtUser1); - final JsonNode paramNode = objectMapper.readTree(res1.readEntity(String.class)); - ((ObjectNode) paramNode).put("name", "test"); - - final String symbolPre = symbolApi.getAll(projectId, jwtUser1).readEntity(String.class); - - final Response res2 = symbolParameterApi.update(projectId, symbolId, paramNode.get("id").asInt(), paramNode.toString(), jwtUser1); - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), res2.getStatus()); - - final String symbolPost = symbolApi.getAll(projectId, jwtUser1).readEntity(String.class); - JSONAssert.assertEquals(symbolPre, symbolPost, true); - } - - @Test - public void shouldUpdateParameterOnSymbolLockedByUser() throws Exception { - WebSocketUser webSocketUser = new WebSocketUser("webSocketUser", client, port); - projectApi.addMembers(Integer.toUnsignedLong(projectId), Collections.singletonList(webSocketUser.getUserId()), jwtUser1); - - symbolParameterApi.create(projectId, symbolId, createOutputStringParam(symbolId, "test"), jwtUser1); - final Response res1 = symbolParameterApi.create(projectId, symbolId, createOutputStringParam(symbolId, "test2"), jwtUser1); - final JsonNode paramNode = objectMapper.readTree(res1.readEntity(String.class)); - ((ObjectNode) paramNode).put("name", "newName"); - - webSocketUser.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId, symbolId)); - Awaitility.await().atMost(defaultWaitTime).until(() -> webSocketUser.assertNumberOfMessages(List.of("default"), List.of(1))); - - final Response res2 = symbolParameterApi.update(projectId, symbolId, paramNode.get("id").asInt(), paramNode.toString(), webSocketUser.getJwt()); - assertEquals(Response.Status.OK.getStatusCode(), res2.getStatus()); - - webSocketUser.forceDisconnectAll(); - } - - @Test - public void shouldNotUpdateParameterOnSymbolLockedByOtherUser() throws Exception { - WebSocketUser webSocketUser = new WebSocketUser("webSocketUser", client, port); - projectApi.addMembers(Integer.toUnsignedLong(projectId), Collections.singletonList(webSocketUser.getUserId()), jwtUser1); - - symbolParameterApi.create(projectId, symbolId, createOutputStringParam(symbolId, "test"), jwtUser1); - final Response res1 = symbolParameterApi.create(projectId, symbolId, createOutputStringParam(symbolId, "test2"), jwtUser1); - final JsonNode paramNode = objectMapper.readTree(res1.readEntity(String.class)); - ((ObjectNode) paramNode).put("name", "newName"); - - webSocketUser.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId, symbolId)); - Awaitility.await().atMost(defaultWaitTime).until(() -> webSocketUser.assertNumberOfMessages(List.of("default"), List.of(1))); - - final Response res2 = symbolParameterApi.update(projectId, symbolId, paramNode.get("id").asInt(), paramNode.toString(), jwtUser1); - assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), res2.getStatus()); - - webSocketUser.forceDisconnectAll(); - } - - @Test - public void shouldDeleteInputParameter() throws Exception { - final Response res1 = symbolParameterApi.create(projectId, symbolId, createInputStringParam(symbolId, "test"), jwtUser1); - final int id = JsonPath.read(res1.readEntity(String.class), "$.id"); - - final Response res2 = symbolParameterApi.delete(projectId, symbolId, id, jwtUser1); - assertEquals(Response.Status.NO_CONTENT.getStatusCode(), res2.getStatus()); - - final JsonNode symbols = objectMapper.readTree(symbolApi.getAll(projectId, jwtUser1).readEntity(String.class)); - assertEquals("[]", symbols.get(0).get("inputs").toString()); - } - - @Test - public void shouldDeleteOutputParameter() throws Exception { - final Response res1 = symbolParameterApi.create(projectId, symbolId, createOutputStringParam(symbolId, "test"), jwtUser1); - final int id = JsonPath.read(res1.readEntity(String.class), "$.id"); - - final Response res2 = symbolParameterApi.delete(projectId, symbolId, id, jwtUser1); - assertEquals(Response.Status.NO_CONTENT.getStatusCode(), res2.getStatus()); - - final JsonNode symbols = objectMapper.readTree(symbolApi.getAll(projectId, jwtUser1).readEntity(String.class)); - assertEquals("[]", symbols.get(0).get("outputs").toString()); - } - - @Test - public void shouldDeleteParameterOnSymbolLockedByUser() throws Exception { - WebSocketUser webSocketUser = new WebSocketUser("webSocketUser", client, port); - projectApi.addMembers(Integer.toUnsignedLong(projectId), Collections.singletonList(webSocketUser.getUserId()), jwtUser1); - - final Response res1 = symbolParameterApi.create(projectId, symbolId, createInputStringParam(symbolId, "test"), jwtUser1); - final int id = JsonPath.read(res1.readEntity(String.class), "$.id"); - - webSocketUser.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId, symbolId)); - Awaitility.await().atMost(defaultWaitTime).until(() -> webSocketUser.assertNumberOfMessages(List.of("default"), List.of(1))); - - final Response res2 = symbolParameterApi.delete(projectId, symbolId, id, webSocketUser.getJwt()); - assertEquals(Response.Status.NO_CONTENT.getStatusCode(), res2.getStatus()); - - webSocketUser.forceDisconnectAll(); - } - - @Test - public void shouldNotDeleteParameterOnSymbolLockedByOtherUser() throws Exception { - WebSocketUser webSocketUser = new WebSocketUser("webSocketUser", client, port); - projectApi.addMembers(Integer.toUnsignedLong(projectId), Collections.singletonList(webSocketUser.getUserId()), jwtUser1); - - final Response res1 = symbolParameterApi.create(projectId, symbolId, createInputStringParam(symbolId, "test"), jwtUser1); - final int id = JsonPath.read(res1.readEntity(String.class), "$.id"); - - webSocketUser.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId, symbolId)); - Awaitility.await().atMost(defaultWaitTime).until(() -> webSocketUser.assertNumberOfMessages(List.of("default"), List.of(1))); - - final Response res2 = symbolParameterApi.delete(projectId, symbolId, id, jwtUser1); - assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), res2.getStatus()); - - webSocketUser.forceDisconnectAll(); - } - - private JsonNode getSymbol() throws Exception { - final Response res = symbolApi.getAll(projectId, jwtUser1); - final String symbols = res.readEntity(String.class); - return om.readTree(symbols).get(0); - } - - private String createInputParam(int symId, String name, String parameterType) { - return "{\"symbol\":\"" + symId + "\"" - + ",\"name\":\"" + name + "\"" - + ",\"type\":\"input\"" - + ",\"parameterType\": \"" + parameterType + "\"}"; - } - - private String createOutputParam(int symId, String name, String parameterType) { - return "{\"symbol\":\"" + symId + "\"" - + ",\"name\":\"" + name + "\"" - + ",\"type\":\"output\"" - + ",\"parameterType\": \"" + parameterType + "\"}"; - } - - private String createInputStringParam(int symId, String name) { - return createInputParam(symId, name, "STRING"); - } - - private String createInputCounterParam(int symId, String name) { - return createInputParam(symId, name, "COUNTER"); - } - - private String createOutputStringParam(int symId, String name) { - return createOutputParam(symId, name, "STRING"); - } - - private String createOutputCounterParam(int symId, String name) { - return createOutputParam(symId, name, "COUNTER"); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/SymbolResourceIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/SymbolResourceIT.java deleted file mode 100644 index b33e4ff7b..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/SymbolResourceIT.java +++ /dev/null @@ -1,838 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.jayway.jsonpath.JsonPath; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolActionStep; -import de.learnlib.alex.data.entities.SymbolGroup; -import de.learnlib.alex.data.entities.SymbolPSymbolStep; -import de.learnlib.alex.data.entities.SymbolStep; -import de.learnlib.alex.data.entities.actions.misc.WaitAction; -import de.learnlib.alex.integrationtests.SpringRestError; -import de.learnlib.alex.integrationtests.resources.api.ProjectApi; -import de.learnlib.alex.integrationtests.resources.api.SymbolApi; -import de.learnlib.alex.integrationtests.resources.api.SymbolGroupApi; -import de.learnlib.alex.integrationtests.resources.api.UserApi; -import de.learnlib.alex.integrationtests.websocket.util.SymbolPresenceServiceWSMessages; -import de.learnlib.alex.integrationtests.websocket.util.WebSocketUser; -import java.io.File; -import java.time.Duration; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.stream.Collectors; -import javax.ws.rs.core.GenericType; -import javax.ws.rs.core.Response; -import org.awaitility.Awaitility; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.skyscreamer.jsonassert.JSONAssert; -import org.springframework.http.HttpStatus; - -public class SymbolResourceIT extends AbstractResourceIT { - - private final Duration defaultWaitTime = Duration.ofSeconds(5); - - private String jwtUser1; - - private String jwtUser2; - - private int userId1; - - private int userId2; - - private int projectId1; - - private int projectId2; - - private int symbolGroupId1; - - private int symbolGroupId2; - - private SymbolApi symbolApi; - - private SymbolGroupApi symbolGroupApi; - - private ProjectApi projectApi; - - private SymbolPresenceServiceWSMessages symbolPresenceServiceWSMessages; - - @BeforeEach - public void pre() throws Exception { - symbolGroupApi = new SymbolGroupApi(client, port); - symbolApi = new SymbolApi(client, port); - final UserApi userApi = new UserApi(client, port); - projectApi = new ProjectApi(client, port); - symbolPresenceServiceWSMessages = new SymbolPresenceServiceWSMessages(); - - final Response res1 = userApi.create("{\"email\":\"test1@test.de\",\"username\":\"test1\",\"password\":\"test\"}"); - final Response res2 = userApi.create("{\"email\":\"test2@test.de\",\"username\":\"test2\",\"password\":\"test\"}"); - - userId1 = JsonPath.read(res1.readEntity(String.class), "id"); - userId2 = JsonPath.read(res2.readEntity(String.class), "id"); - - jwtUser1 = userApi.login("test1@test.de", "test"); - jwtUser2 = userApi.login("test2@test.de", "test"); - - final Response res3 = - projectApi.create("{\"name\":\"test\",\"url\":\"http://localhost:8080/"}", jwtUser1); - final Response res4 = - projectApi.create("{\"name\":\"test\",\"url\":\"http://localhost:8080/"}", jwtUser2); - - projectId1 = JsonPath.read(res3.readEntity(String.class), "id"); - projectId2 = JsonPath.read(res4.readEntity(String.class), "id"); - - final Response res5 = - symbolGroupApi.create(projectId1, "{\"name\":\"group1\", \"project\": " + projectId1 + "}", jwtUser1); - final Response res6 = - symbolGroupApi.create(projectId2, "{\"name\":\"group2\", \"project\": " + projectId2 + "}", jwtUser2); - - symbolGroupId1 = JsonPath.read(res5.readEntity(String.class), "id"); - symbolGroupId2 = JsonPath.read(res6.readEntity(String.class), "id"); - } - - @Test - public void shouldCreateADefaultSymbol() throws Exception { - final String symbol = createSymbolWithProjectJson(projectId1, "s1"); - final Response res = symbolApi.create(projectId1, symbol, jwtUser1); - - assertEquals(HttpStatus.CREATED.value(), res.getStatus()); - assertEquals(1, getNumberOfSymbols(projectId1, jwtUser1)); - } - - @Test - public void shouldCreateASymbolWithAllProperties() throws Exception { - final String symbolJson = createSymbolWithAllPropertiesJson(projectId1, symbolGroupId1, "s1"); - final Response res1 = symbolApi.create(projectId1, symbolJson, jwtUser1); - - assertEquals(HttpStatus.CREATED.value(), res1.getStatus()); - final String symbolRes = res1.readEntity(String.class); - final JsonNode symbolNode = objectMapper.readTree(symbolJson); - ((ObjectNode) symbolNode).put("id", objectMapper.readTree(symbolRes).get("id").intValue()); - ((ObjectNode) symbolNode).put("updatedOn", objectMapper.readTree(symbolRes).get("updatedOn").asText()); - ((ObjectNode) symbolNode).set("lastUpdatedBy", objectMapper.readTree(symbolRes).get("lastUpdatedBy")); - JSONAssert.assertEquals(symbolNode.toString(), symbolRes, true); - - final Response res2 = symbolApi.getAll(projectId1, jwtUser1); - final String symbol = objectMapper.readTree(res2.readEntity(String.class)).get(0).toString(); - JSONAssert.assertEquals(symbolNode.toString(), symbol, true); - } - - @Test - public void shouldGetAllSymbols() throws Exception { - final String symbol1 = createSymbolWithProjectJson(projectId1, "s1"); - final String symbol2 = createSymbolWithProjectJson(projectId1, "s2"); - final String symbol3 = createSymbolWithProjectJson(projectId1, "s3"); - - symbolApi.create(projectId1, symbol1, jwtUser1); - symbolApi.create(projectId1, symbol2, jwtUser1); - symbolApi.create(projectId1, symbol3, jwtUser1); - assertEquals(3, getNumberOfSymbols(projectId1, jwtUser1)); - } - - @Test - public void shouldUpdateSymbolLockedByUser() throws Exception { - WebSocketUser webSocketUser = new WebSocketUser("webSocketUser", client, port); - projectApi.addMembers(Integer.toUnsignedLong(projectId1), Collections.singletonList(webSocketUser.getUserId()), jwtUser1); - - final Symbol s = createSymbol("s", (long) projectId1, jwtUser1); - - webSocketUser.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, s.getId())); - Awaitility.await().atMost(defaultWaitTime).until(() -> webSocketUser.assertNumberOfMessages("default", 1)); - - s.setName("s2"); - - Response res = symbolApi.update(Math.toIntExact(s.getProjectId()), s.getId(), objectMapper.writeValueAsString(s), webSocketUser.getJwt()); - assertEquals(Response.Status.OK.getStatusCode(), res.getStatus()); - - webSocketUser.forceDisconnectAll(); - } - - @Test - public void shouldFailToUpdateSymbolLockedByUser() throws Exception { - WebSocketUser webSocketUser = new WebSocketUser("webSocketUser", client, port); - projectApi.addMembers(Integer.toUnsignedLong(projectId1), Collections.singletonList(webSocketUser.getUserId()), jwtUser1); - - final Symbol s = createSymbol("s", (long) projectId1, jwtUser1); - - webSocketUser.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, s.getId())); - Awaitility.await().atMost(defaultWaitTime).until(() -> webSocketUser.assertNumberOfMessages("default", 1)); - - s.setName("s2"); - - Response res = symbolApi.update(Math.toIntExact(s.getProjectId()), s.getId(), objectMapper.writeValueAsString(s), webSocketUser.getJwt()); - assertEquals(Response.Status.OK.getStatusCode(), res.getStatus()); - - webSocketUser.forceDisconnectAll(); - } - - @Test - public void shouldUpdateSymbolStepsWithSymbolUpdate() throws Exception { - Symbol s = createSymbol("s", (long) projectId1, jwtUser1); - - final WaitAction a = new WaitAction(); - a.setDuration(1L); - - final SymbolActionStep step1 = new SymbolActionStep(); - step1.setAction(a); - - final SymbolActionStep step2 = new SymbolActionStep(); - step2.setAction(a); - - s.getSteps().add(step1); - s.getSteps().add(step2); - - final Response res = symbolApi.update(projectId1, s.getId(), objectMapper.writeValueAsString(s), jwtUser1); - s = res.readEntity(Symbol.class); - - assertEquals(HttpStatus.OK.value(), res.getStatus()); - assertEquals(2, s.getSteps().size()); - } - - @Test - public void shouldMergeSymbolStepsOnUpdate() throws Exception { - Symbol s = createSymbolWithSteps(); - - final Long symbolStepIdToDelete = s.getSteps().get(0).getId(); - final Long symbolStepIdToKeep = s.getSteps().get(1).getId(); - - s.getSteps().removeIf(st -> st.getId().equals(symbolStepIdToDelete)); - - final WaitAction a = new WaitAction(); - a.setDuration(1L); - - final SymbolActionStep step3 = new SymbolActionStep(); - step3.setAction(a); - - s.getSteps().add(step3); - - final Response res2 = symbolApi.update(projectId1, s.getId(), objectMapper.writeValueAsString(s), jwtUser1); - s = res2.readEntity(Symbol.class); - - assertEquals(HttpStatus.OK.value(), res2.getStatus()); - assertEquals(2, s.getSteps().size()); - assertEquals(symbolStepIdToKeep, s.getSteps().get(0).getId()); - assertNotEquals(symbolStepIdToDelete, s.getSteps().get(1).getId()); - } - - @Test - public void shouldUpdateOrderOfStepsOnSymbolUpdate() throws Exception { - Symbol s = createSymbolWithSteps(); - - final SymbolStep step1 = s.getSteps().get(0); - final SymbolStep step2 = s.getSteps().get(1); - - s.getSteps().clear(); - s.getSteps().add(step2); - s.getSteps().add(step1); - - final Response res = symbolApi.update(projectId1, s.getId(), objectMapper.writeValueAsString(s), jwtUser1); - s = res.readEntity(Symbol.class); - - assertEquals(HttpStatus.OK.value(), res.getStatus()); - assertEquals(step2.getId(), s.getSteps().get(0).getId()); - assertEquals(step1.getId(), s.getSteps().get(1).getId()); - } - - @Test - public void shouldSaveSymbolWithSymbolStep() throws Exception { - final Symbol s1 = createSymbol("s1", (long) projectId1, jwtUser1); - final Symbol s2 = createSymbol("s2", (long) projectId1, jwtUser1); - - final ParameterizedSymbol pSymbol = new ParameterizedSymbol(); - pSymbol.setSymbol(s2); - - final SymbolPSymbolStep step = new SymbolPSymbolStep(); - step.setPSymbol(pSymbol); - s1.getSteps().add(step); - - final Response res = symbolApi.update(projectId1, s1.getId(), objectMapper.writeValueAsString(s1), jwtUser1); - final Symbol updatedSymbol = res.readEntity(Symbol.class); - - assertEquals(HttpStatus.OK.value(), res.getStatus()); - assertEquals(1, updatedSymbol.getSteps().size()); - - final SymbolPSymbolStep pSymbolStep = (SymbolPSymbolStep) updatedSymbol.getSteps().get(0); - assertEquals(s2.getId(), pSymbolStep.getPSymbol().getSymbol().getId()); - } - - @Test - public void shouldFailToSaveSymbolThatReferencesItself() throws Exception { - Symbol s1 = createSymbol("s1", (long) projectId1, jwtUser1); - - final Symbol s1ref = new Symbol(); - s1ref.setId(s1.getId()); - - final ParameterizedSymbol pSymbol = new ParameterizedSymbol(); - pSymbol.setSymbol(s1ref); - - final SymbolPSymbolStep step = new SymbolPSymbolStep(); - step.setPSymbol(pSymbol); - s1.getSteps().add(step); - - final Response res = symbolApi.update(projectId1, s1.getId(), objectMapper.writeValueAsString(s1), jwtUser1); - s1 = symbolApi.get(projectId1, s1.getId(), jwtUser1).readEntity(Symbol.class); - - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - assertEquals(0, s1.getSteps().size()); - } - - private Symbol createSymbolWithSteps() throws Exception { - Symbol s = createSymbol("s", (long) projectId1, jwtUser1); - - final WaitAction a = new WaitAction(); - a.setDuration(1L); - - final SymbolActionStep step1 = new SymbolActionStep(); - step1.setAction(a); - - final SymbolActionStep step2 = new SymbolActionStep(); - step2.setAction(a); - - final SymbolActionStep step3 = new SymbolActionStep(); - step3.setAction(a); - - s.getSteps().add(step1); - s.getSteps().add(step2); - - final Response res = symbolApi.update(projectId1, s.getId(), objectMapper.writeValueAsString(s), jwtUser1); - return res.readEntity(Symbol.class); - } - - @Test - public void shouldNotCreateASymbolIfNameExistsInTheSameGroup() throws Exception { - final String symbol1 = createSymbolWithProjectJson(projectId1, "s1"); - final String symbol2 = createSymbolWithProjectJson(projectId1, "s1"); - - symbolApi.create(projectId1, symbol1, jwtUser1); - final Response res = symbolApi.create(projectId1, symbol2, jwtUser1); - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - assertEquals(1, getNumberOfSymbols(projectId1, jwtUser1)); - } - - @Test - public void shouldCreateASymbolInAGroup() { - final String symbolJson = createSymbolWithGroupJson(projectId1, symbolGroupId1, "s1"); - final Response res1 = symbolApi.create(projectId1, symbolJson, jwtUser1); - assertEquals(HttpStatus.CREATED.value(), res1.getStatus()); - - final String symbol = res1.readEntity(String.class); - final int groupId = JsonPath.read(symbol, "$.group"); - assertEquals(symbolGroupId1, groupId); - - final Response res2 = symbolGroupApi.getAll(projectId1, jwtUser1); - final var groups = res2.readEntity(new GenericType>() { - }); - final var numberOfSymbols = groups.stream() - .filter(g -> g.getName().equals("group1")) - .findFirst() - .map(g -> g.getSymbols().size()) - .orElse(0); - - assertEquals(1, (int) numberOfSymbols); - } - - @Test - public void shouldGetASymbolByItsId() throws Exception { - final Symbol s = createSymbol("sym", (long) projectId1, jwtUser1); - final Response res2 = symbolApi.get(projectId1, s.getId(), jwtUser1); - final Symbol symbol = res2.readEntity(Symbol.class); - - assertEquals(HttpStatus.OK.value(), res2.getStatus()); - assertEquals(s.getId(), symbol.getId()); - assertEquals("sym", symbol.getName()); - } - - @Test - public void shouldReturn404IfSymbolIdIsNotFoundWhenGettingASymbolById() throws Exception { - final Response res = symbolApi.get(projectId1, -1L, jwtUser1); - assertEquals(HttpStatus.NOT_FOUND.value(), res.getStatus()); - res.readEntity(SpringRestError.class); - } - - @Test - public void shouldGetMultipleSymbolsByTheirIds() throws Exception { - final Symbol s1 = createSymbol("s1", (long) projectId1, jwtUser1); - final Symbol s2 = createSymbol("s2", (long) projectId1, jwtUser1); - final Symbol s3 = createSymbol("s3", (long) projectId1, jwtUser1); - - final Response res = symbolApi.get(projectId1, Arrays.asList(s1.getId(), s3.getId()), jwtUser1); - final List symbols = res.readEntity(new GenericType<>() { - }); - final List symbolIds = symbols.stream().map(Symbol::getId).collect(Collectors.toList()); - - assertEquals(HttpStatus.OK.value(), res.getStatus()); - assertEquals(2, symbolIds.size()); - assertTrue(symbolIds.contains(s1.getId())); - assertTrue(symbolIds.contains(s3.getId())); - } - - @Test - public void shouldUpdateNameExpectedResultAndDescriptionOfASymbol() throws Exception { - final Symbol s1 = createSymbol("s1", (long) projectId1, jwtUser1); - s1.setName("updatedName"); - s1.setDescription("updatedDescription"); - s1.setExpectedResult("updatedExpectedResult"); - - final Response res = symbolApi.update(projectId1, s1.getId(), objectMapper.writeValueAsString(s1), jwtUser1); - final Symbol updatedSymbol = res.readEntity(Symbol.class); - assertEquals(HttpStatus.OK.value(), res.getStatus()); - assertEquals(s1.getName(), updatedSymbol.getName()); - assertEquals(s1.getDescription(), updatedSymbol.getDescription()); - assertEquals(s1.getExpectedResult(), updatedSymbol.getExpectedResult()); - } - - @Test - public void shouldUpdateTimestampOnUpdate() throws Exception { - final Symbol s1 = createSymbol("s1", (long) projectId1, jwtUser1); - s1.setName("updatedName"); - - final Response res = symbolApi.update(projectId1, s1.getId(), objectMapper.writeValueAsString(s1), jwtUser1); - final Symbol updatedSymbol = res.readEntity(Symbol.class); - - assertEquals(HttpStatus.OK.value(), res.getStatus()); - assertTrue(updatedSymbol.getUpdatedOn().isAfter(s1.getUpdatedOn())); - } - - @Test - public void shouldUpdateModifiedByOnUpdate() throws Exception { - projectApi.addOwners((long) projectId1, Collections.singletonList((long) userId2), jwtUser1); - - final Symbol s1 = createSymbol("s1", (long) projectId1, jwtUser1); - s1.setName("updatedName"); - - final Response res = symbolApi.update(projectId1, s1.getId(), objectMapper.writeValueAsString(s1), jwtUser2); - final Symbol updatedSymbol = res.readEntity(Symbol.class); - - assertEquals(HttpStatus.OK.value(), res.getStatus()); - assertEquals((long) updatedSymbol.getLastUpdatedBy().getId(), userId2); - } - - @Test - public void shouldMoveSymbolToAnotherGroup() throws Exception { - Symbol s = createSymbol("s", (long) projectId1, jwtUser1); - final SymbolGroup g = createGroup("g", (long) projectId1, jwtUser1); - - final Response res = symbolApi.move(projectId1, s.getId(), g.getId(), jwtUser1); - s = symbolApi.get(projectId1, s.getId(), jwtUser1).readEntity(Symbol.class); - - assertEquals(HttpStatus.OK.value(), res.getStatus()); - assertEquals(g.getId(), s.getGroupId()); - } - - @Test - public void shouldMoveSymbolsToAnotherGroup() throws Exception { - final SymbolGroup g = createGroup("g", (long) projectId1, jwtUser1); - Symbol s1 = createSymbol("s1", (long) projectId1, jwtUser1); - Symbol s2 = createSymbol("s2", (long) projectId1, jwtUser1); - - final Response res = symbolApi.move(projectId1, Arrays.asList(s1.getId(), s2.getId()), g.getId(), jwtUser1); - s1 = symbolApi.get(projectId1, s1.getId(), jwtUser1).readEntity(Symbol.class); - s2 = symbolApi.get(projectId1, s2.getId(), jwtUser1).readEntity(Symbol.class); - - assertEquals(HttpStatus.OK.value(), res.getStatus()); - assertEquals(g.getId(), s1.getGroupId()); - assertEquals(g.getId(), s2.getGroupId()); - } - - @Test - public void shouldFailToMoveSymbolToAnotherGroupWithASymbolWithTheSameName() throws Exception { - final Symbol s1 = createSymbol("s1", (long) projectId1, jwtUser1); - final SymbolGroup g = createGroup("g", (long) projectId1, jwtUser1); - - final String symbolJson = createSymbolWithGroupJson(projectId1, Math.toIntExact(g.getId()), "s1"); - final Response res1 = symbolApi.create(projectId1, symbolJson, jwtUser1); - assertEquals(HttpStatus.CREATED.value(), res1.getStatus()); - - final Response res = symbolApi.move(projectId1, s1.getId(), g.getId(), jwtUser1); - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - } - - @Test - public void shouldNotMoveLockedSymbol() throws Exception { - WebSocketUser webSocketUser = new WebSocketUser("webSocketUser", client, port); - projectApi.addMembers(Integer.toUnsignedLong(projectId1), Collections.singletonList(webSocketUser.getUserId()), jwtUser1); - - final SymbolGroup g = createGroup("g", (long) projectId1, jwtUser1); - Symbol s1 = createSymbol("s1", (long) projectId1, jwtUser1); - - webSocketUser.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, s1.getId())); - Awaitility.await().atMost(defaultWaitTime).until(() -> webSocketUser.assertNumberOfMessages("default", 1)); - - final Response res = symbolApi.move(projectId1, s1.getId(), g.getId(), webSocketUser.getJwt()); - - assertEquals(HttpStatus.UNAUTHORIZED.value(), res.getStatus()); - } - - @Test - public void shouldNotDeleteSymbolThatIsNotArchived() throws Exception { - final Symbol s = createSymbol("s", (long) projectId1, jwtUser1); - - final Response res = symbolApi.delete(projectId1, s.getId(), jwtUser1); - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - res.readEntity(SpringRestError.class); - - final SymbolGroup group = symbolGroupApi.get((long) projectId1, s.getGroupId(), jwtUser1).readEntity(SymbolGroup.class); - assertEquals(1, group.getSymbols().size()); - } - - @Test - public void shouldDeleteSymbol() throws Exception { - final Symbol s = createSymbol("s", (long) projectId1, jwtUser1); - symbolApi.archive(projectId1, s.getId().intValue(), jwtUser1); - - final Response res = symbolApi.delete(projectId1, s.getId(), jwtUser1); - - assertEquals(HttpStatus.NO_CONTENT.value(), res.getStatus()); - assertEquals("", res.readEntity(String.class)); - - final SymbolGroup group = symbolGroupApi.get((long) projectId1, s.getGroupId(), jwtUser1).readEntity(SymbolGroup.class); - assertEquals(0, group.getSymbols().size()); - } - - @Test - public void shouldNotDeleteLockedSymbol() throws Exception { - WebSocketUser webSocketUser = new WebSocketUser("webSocketUser", client, port); - projectApi.addMembers(Integer.toUnsignedLong(projectId1), Collections.singletonList(webSocketUser.getUserId()), jwtUser1); - - final Symbol s = createSymbol("s", (long) projectId1, jwtUser1); - symbolApi.archive(projectId1, s.getId().intValue(), jwtUser1); - - webSocketUser.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, s.getId())); - Awaitility.await().atMost(defaultWaitTime).until(() -> webSocketUser.assertNumberOfMessages("default", 1)); - - final Response res = symbolApi.delete(projectId1, s.getId(), webSocketUser.getJwt()); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res.getStatus()); - - webSocketUser.forceDisconnectAll(); - } - - @Test - public void shouldDeleteSymbolsByIds() throws Exception { - final Symbol s1 = createSymbol("s1", (long) projectId1, jwtUser1); - final Symbol s2 = createSymbol("s2", (long) projectId1, jwtUser1); - - symbolApi.archiveMany(projectId1, Arrays.asList(s1.getId().intValue(), s2.getId().intValue()), jwtUser1); - final Response res = symbolApi.delete(projectId1, Arrays.asList(s1.getId(), s2.getId()), jwtUser1); - - assertEquals(HttpStatus.NO_CONTENT.value(), res.getStatus()); - assertEquals("", res.readEntity(String.class)); - - final SymbolGroup group = symbolGroupApi.get((long) projectId1, s1.getGroupId(), jwtUser1).readEntity(SymbolGroup.class); - assertEquals(0, group.getSymbols().size()); - } - - @Test - public void shouldRestoreSymbolFromTheArchive() throws Exception { - Symbol s1 = createSymbol("s1", (long) projectId1, jwtUser1); - symbolApi.archive(projectId1, s1.getId().intValue(), jwtUser1); - - final Response res = symbolApi.restore((long) projectId1, s1.getId(), jwtUser1); - final Symbol restoredSymbol = res.readEntity(Symbol.class); - - s1 = symbolApi.get(projectId1, s1.getId(), jwtUser1).readEntity(Symbol.class); - - assertEquals(HttpStatus.OK.value(), res.getStatus()); - assertFalse(restoredSymbol.isHidden()); - assertFalse(s1.isHidden()); - } - - @Test - public void shouldRestoreSymbolsFromTheArchive() throws Exception { - Symbol s1 = createSymbol("s1", (long) projectId1, jwtUser1); - Symbol s2 = createSymbol("s2", (long) projectId1, jwtUser1); - symbolApi.archive(projectId1, s1.getId().intValue(), jwtUser1); - symbolApi.archive(projectId1, s2.getId().intValue(), jwtUser1); - - final Response res = symbolApi.restore((long) projectId1, Arrays.asList(s1.getId(), s2.getId()), jwtUser1); - final List restoredSymbols = res.readEntity(new GenericType<>() { - }); - - s1 = symbolApi.get(projectId1, s1.getId(), jwtUser1).readEntity(Symbol.class); - s2 = symbolApi.get(projectId1, s2.getId(), jwtUser1).readEntity(Symbol.class); - - assertEquals(HttpStatus.OK.value(), res.getStatus()); - for (Symbol s : restoredSymbols) { - assertFalse(s.isHidden()); - } - assertFalse(s1.isHidden()); - assertFalse(s2.isHidden()); - } - - private SymbolGroup createGroup(String name, Long projectId, String jwt) throws Exception { - final SymbolGroup s = new SymbolGroup(); - s.setProjectId(projectId); - s.setName(name); - - final Response res = symbolGroupApi.create(projectId1, objectMapper.writeValueAsString(s), jwt); - return res.readEntity(SymbolGroup.class); - } - - private Symbol createSymbol(String name, Long projectId, String jwt) throws Exception { - final Symbol s = new Symbol(); - s.setProjectId(projectId); - s.setName(name); - - final Response res = symbolApi.create(projectId1, objectMapper.writeValueAsString(s), jwt); - return res.readEntity(Symbol.class); - } - - @Test - public void shouldNotCreateASymbolInANonExistingGroup() throws Exception { - final String symbolJson = createSymbolWithGroupJson(projectId1, -1, "s1"); - final Response res1 = symbolApi.create(projectId1, symbolJson, jwtUser1); - assertEquals(HttpStatus.NOT_FOUND.value(), res1.getStatus()); - assertEquals(0, getNumberOfSymbols(projectId1, jwtUser1)); - } - - @Test - public void shouldNotCreateASymbolInAnotherUsersGroup() throws Exception { - final String symbolJson = createSymbolWithGroupJson(projectId1, symbolGroupId2, "s1"); - final Response res1 = symbolApi.create(projectId1, symbolJson, jwtUser1); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res1.getStatus()); - assertEquals(0, getNumberOfSymbols(projectId1, jwtUser1)); - assertEquals(0, getNumberOfSymbols(projectId2, jwtUser2)); - } - - @Test - public void shouldNotCreateASymbolInAnotherUsersProject() throws Exception { - final String symbol = createSymbolWithProjectJson(projectId2, "s1"); - final Response res = symbolApi.create(projectId2, symbol, jwtUser1); - - assertEquals(HttpStatus.UNAUTHORIZED.value(), res.getStatus()); - assertEquals(0, getNumberOfSymbols(projectId1, jwtUser1)); - assertEquals(0, getNumberOfSymbols(projectId2, jwtUser2)); - } - - @Test - public void shouldCreateASymbolsWithActionSteps() throws Exception { - final String symbolJson = createSymbolWithActionStepsJson(projectId1, "s1"); - final Response res = symbolApi.create(projectId1, symbolJson, jwtUser1); - - assertEquals(HttpStatus.CREATED.value(), res.getStatus()); - assertEquals(1, getNumberOfSymbols(projectId1, jwtUser1)); - - final String symbol = res.readEntity(String.class); - validateSymbol(symbol, projectId1); - } - - @Test - public void shouldCreateSymbolsWithActionSteps() throws Exception { - final String symbolJson1 = createSymbolWithActionStepsJson(projectId1, "s1"); - final String symbolJson2 = createSymbolWithActionStepsJson(projectId1, "s2"); - final String symbolsJson = "[" + String.join(",", Arrays.asList(symbolJson1, symbolJson2)) + "]"; - final Response res = symbolApi.createMany(projectId1, symbolsJson, jwtUser1); - - assertEquals(HttpStatus.CREATED.value(), res.getStatus()); - assertEquals(2, getNumberOfSymbols(projectId1, jwtUser1)); - - final String symbols = res.readEntity(String.class); - final JsonNode symbolsNode = objectMapper.readTree(symbols); - validateSymbol(symbolsNode.get(0).toString(), projectId1); - validateSymbol(symbolsNode.get(1).toString(), projectId1); - } - - @Test - public void shouldHideASymbol() throws Exception { - final String symbolJson = createSymbolWithActionStepsJson(projectId1, "s1"); - final Response res1 = symbolApi.create(projectId1, symbolJson, jwtUser1); - - final String symbol = res1.readEntity(String.class); - final int symbolId = JsonPath.read(symbol, "$.id"); - - final Response res2 = symbolApi.archive(projectId1, symbolId, jwtUser1); - assertEquals(HttpStatus.OK.value(), res2.getStatus()); - assertEquals(0, getNumberOfSymbols(projectId1, jwtUser1)); - - final String archivedSymbol = res2.readEntity(String.class); - final boolean hidden = JsonPath.read(archivedSymbol, "$.hidden"); - assertTrue(hidden); - } - - @Test - public void shouldHideSymbols() throws Exception { - final String symbolJson1 = createSymbolWithActionStepsJson(projectId1, "s1"); - final String symbolJson2 = createSymbolWithActionStepsJson(projectId1, "s2"); - final String symbolsJson = "[" + String.join(",", Arrays.asList(symbolJson1, symbolJson2)) + "]"; - final Response res = symbolApi.createMany(projectId1, symbolsJson, jwtUser1); - - final String symbols = res.readEntity(String.class); - final int symbol1Id = JsonPath.read(symbols, "$.[0].id"); - final int symbol2Id = JsonPath.read(symbols, "$.[1].id"); - - final Response res2 = symbolApi.archiveMany(projectId1, Arrays.asList(symbol1Id, symbol2Id), jwtUser1); - assertEquals(HttpStatus.OK.value(), res2.getStatus()); - assertEquals(0, getNumberOfSymbols(projectId1, jwtUser1)); - - final String archivedSymbols = res2.readEntity(String.class); - final boolean hidden1 = JsonPath.read(archivedSymbols, "$.[0].hidden"); - final boolean hidden2 = JsonPath.read(archivedSymbols, "$.[1].hidden"); - - assertTrue(hidden1); - assertTrue(hidden2); - } - - @Test - public void shouldCreateSymbolsWithSymbolSteps() throws Exception { - final Response resS2 = symbolApi.create(projectId1, createSymbolWithAllPropertiesJson(projectId1, symbolGroupId1, "s2"), jwtUser1); - final Response resS3 = symbolApi.create(projectId1, createSymbolWithAllPropertiesJson(projectId1, symbolGroupId1, "s3"), jwtUser1); - - final int s2Id = JsonPath.read(resS2.readEntity(String.class), "id"); - final int s3Id = JsonPath.read(resS3.readEntity(String.class), "id"); - - final String symbolWithSymbolStepsJson = createSymbolWithSymbolStepsJson(projectId1, symbolGroupId1, "s1", s2Id, s3Id); - final Response resS1 = symbolApi.create(projectId1, symbolWithSymbolStepsJson, jwtUser1); - assertEquals(HttpStatus.CREATED.value(), resS1.getStatus()); - - final JsonNode symbolsNode = objectMapper.readTree(symbolApi.getAll(projectId1, jwtUser1).readEntity(String.class)); - - final Iterator it = symbolsNode.iterator(); - while (it.hasNext()) { - final JsonNode symbolNode = it.next(); - if (symbolNode.get("name").asText().equals("s1")) { - assertEquals(2, symbolNode.get("steps").size()); - return; - } - } - - throw new Exception("symbol not found"); - } - - @Test - public void shouldCreateASymbolWithAllWebActions() throws Exception { - final File file = new File(getClass().getResource("/core/entities/symbol-with-all-web-actions.json").toURI()); - final JsonNode symbolJson = objectMapper.readTree(file); - final int numberOfSteps = symbolJson.get("steps").size(); - - final Response response = symbolApi.create(projectId1, symbolJson.toString(), jwtUser1); - assertEquals(HttpStatus.CREATED.value(), response.getStatus()); - final JsonNode symbol = objectMapper.readTree(response.readEntity(String.class)); - - assertEquals(numberOfSteps, symbol.get("steps").size()); - } - - @Test - public void shouldCreateASymbolWithAllRestActions() throws Exception { - final File file = new File(getClass().getResource("/core/entities/symbol-with-all-rest-actions.json").toURI()); - final JsonNode symbolJson = objectMapper.readTree(file); - final int numberOfSteps = symbolJson.get("steps").size(); - - final Response response = symbolApi.create(projectId1, symbolJson.toString(), jwtUser1); - assertEquals(HttpStatus.CREATED.value(), response.getStatus()); - final JsonNode symbol = objectMapper.readTree(response.readEntity(String.class)); - - assertEquals(numberOfSteps, symbol.get("steps").size()); - } - - @Test - public void shouldCreateASymbolWithAllMiscActions() throws Exception { - final File file = new File(getClass().getResource("/core/entities/symbol-with-all-misc-actions.json").toURI()); - final JsonNode symbolJson = objectMapper.readTree(file); - final int numberOfSteps = symbolJson.get("steps").size(); - - final Response response = symbolApi.create(projectId1, symbolJson.toString(), jwtUser1); - assertEquals(HttpStatus.CREATED.value(), response.getStatus()); - final JsonNode symbol = objectMapper.readTree(response.readEntity(String.class)); - - assertEquals(numberOfSteps, symbol.get("steps").size()); - } - - private void validateSymbol(String symbol, int projectId) { - int symbolId = JsonPath.read(symbol, "$.id"); - int symbolProjectId = JsonPath.read(symbol, "$.project"); - JsonPath.read(symbol, "$.steps[0].id"); - JsonPath.read(symbol, "$.steps[0].id"); - int step1SymbolId = JsonPath.read(symbol, "$.steps[0].symbol"); - int step2SymbolId = JsonPath.read(symbol, "$.steps[1].symbol"); - JsonPath.read(symbol, "$.steps[0].action.id"); - JsonPath.read(symbol, "$.steps[1].action.id"); - - assertEquals(projectId, symbolProjectId); - assertEquals(symbolId, step1SymbolId); - assertEquals(symbolId, step2SymbolId); - } - - private int getNumberOfSymbols(int projectId, String jwt) throws Exception { - final Response res = symbolApi.getAll(projectId, jwt); - return objectMapper.readTree(res.readEntity(String.class)).size(); - } - - private String createSymbolWithActionStepsJson(int projectId, String name) { - return "{" - + "\"name\":\"" + name + "\"" - + ",\"project\": " + projectId - + ",\"steps\": [" - + "{\"type\":\"action\", \"negated\": false, \"errorOutput\": null, \"ignoreFailure\": false, \"disabled\": false, \"action\": {\"type\": \"wait\", \"duration\": 1000}}" - + ",{\"type\":\"action\", \"negated\": false, \"errorOutput\": null, \"ignoreFailure\": false, \"disabled\": false, \"action\": {\"type\": \"wait\", \"duration\": 1000}}" - + "]" - + "}"; - } - - private String createSymbolWithSymbolStepsJson(int projectId, int groupId, String name, int stepId1, int stepId2) { - return "{" - + "\"name\":\"" + name + "\"" - + ",\"project\": " + projectId - + ",\"group\": " + groupId - + ",\"steps\": [" - + "{\"type\":\"symbol\", \"negated\": false, \"errorOutput\": null, \"ignoreFailure\": false, \"disabled\": false, \"pSymbol\": {\"symbol\": {\"id\": " + stepId1 + "}, \"parameterValues\": []}}" - + ",{\"type\":\"symbol\", \"negated\": false, \"errorOutput\": null, \"ignoreFailure\": false, \"disabled\": false, \"pSymbol\": {\"symbol\": {\"id\": " + stepId2 + "}, \"parameterValues\": []}}" - + "]" - + "}"; - } - - private String createSymbolWithProjectJson(int projectId, String name) { - return "{" - + "\"name\":\"" + name + "\"" - + ",\"project\": " + projectId - + ",\"steps\": []" - + "}"; - } - - private String createSymbolWithGroupJson(int projectId, int groupId, String name) { - return "{" - + "\"name\":\"" + name + "\"" - + ",\"project\": " + projectId - + ",\"group\":" + groupId - + ",\"steps\": []" - + "}"; - } - - private String createSymbolWithAllPropertiesJson(int projectId, int groupId, String name) { - return "{" - + "\"name\":\"" + name + "\"" - + ",\"project\": " + projectId - + ",\"group\":" + groupId - + ",\"steps\": []" - + ",\"description\": \"test description\"" - + ",\"expectedResult\": \"test\"" - + ",\"hidden\": false" - + ",\"inputs\": []" - + ",\"outputs\": []" - + ",\"successOutput\": \"yep\"" - + "}"; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/UserResourceIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/UserResourceIT.java deleted file mode 100644 index 060126c51..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/UserResourceIT.java +++ /dev/null @@ -1,504 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.fasterxml.jackson.databind.JsonNode; -import com.jayway.jsonpath.JsonPath; -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.auth.entities.UserRole; -import de.learnlib.alex.integrationtests.SpringRestError; -import de.learnlib.alex.integrationtests.resources.api.SettingsApi; -import de.learnlib.alex.integrationtests.resources.api.UserApi; -import de.learnlib.alex.settings.entities.Settings; -import java.util.Arrays; -import java.util.List; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.GenericType; -import javax.ws.rs.core.Response; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; -import org.junit.jupiter.params.provider.ValueSource; -import org.skyscreamer.jsonassert.JSONAssert; -import org.springframework.http.HttpStatus; - -public class UserResourceIT extends AbstractResourceIT { - - private UserApi userApi; - - private SettingsApi settingsApi; - - private String adminJwt; - - @BeforeEach - public void pre() { - userApi = new UserApi(client, port); - settingsApi = new SettingsApi(client, port); - adminJwt = userApi.login(ADMIN_EMAIL, ADMIN_PASSWORD); - } - - @Test - public void shouldCreateAnAccount() { - final Response res = userApi.create(createUserJson("test@test.de", "test")); - - assertEquals(HttpStatus.CREATED.value(), res.getStatus()); - JsonPath.read(res.readEntity(String.class), "id"); - } - - @Test - public void shouldFailToGetAJwtIfUserIsInvalid() { - final Response res = client.target(userApi.url() + "/login").request() - .post(Entity.json(createUserJson("test@test.de", "test"))); - - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - - final String body = res.readEntity(String.class); - assertThrows(IllegalArgumentException.class, () -> JsonPath.read(body, "token")); - } - - @Test - public void shouldNotCreateAnAdminAccount() { - final Response res = userApi.create(createUserJson("test@test.de", "test", "ADMIN")); - - assertEquals(HttpStatus.CREATED.value(), res.getStatus()); - assertEquals("REGISTERED", JsonPath.read(res.readEntity(String.class), "role")); - } - - @ParameterizedTest(name = "Use value \"{0}\" for the test") - @ValueSource(strings = { "", "asd", "@test.de" }) - public void shouldNotCreateAUserWithInvalidEmail(String email) { - final Response res = userApi.create(createUserJson(email, "test")); - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - } - - @Test - public void shouldNotCreateTheSameUserTwice() { - final Response res1 = userApi.create(createUserJson("test@test.de", "test")); - assertEquals(HttpStatus.CREATED.value(), res1.getStatus()); - - final Response res2 = userApi.create(createUserJson("test@test.de", "test")); - assertEquals(HttpStatus.BAD_REQUEST.value(), res2.getStatus()); - } - - @Test - public void userShouldNotBeAbleToPromoteHimself() { - final Response res1 = userApi.create(createUserJson("test@test.de", "test")); - - final int userId = JsonPath.read(res1.readEntity(String.class), "id"); - final String jwt = userApi.login("test@test.de", "test"); - - final Response res2 = userApi.changeRole(userId, UserRole.ADMIN, jwt); - - assertEquals(HttpStatus.FORBIDDEN.value(), res2.getStatus()); - } - - @Test - public void adminShouldMakeOtherUsersAdmin() { - final Response res1 = userApi.create(createUserJson("test@test.de", "test")); - final int userId = JsonPath.read(res1.readEntity(String.class), "id"); - - userApi.changeRole(userId, UserRole.ADMIN, adminJwt); - - final String jwtUser = userApi.login("test@test.de", "test"); - final Response res2 = userApi.getProfile(jwtUser); - - assertEquals("ADMIN", JsonPath.read(res2.readEntity(String.class), "role")); - } - - @Test - public void adminShouldMakeOtherAdminsUsers() { - final Response res1 = userApi.create(createUserJson("test@test.de", "test"), adminJwt); - final int userId = JsonPath.read(res1.readEntity(String.class), "id"); - userApi.changeRole(userId, UserRole.ADMIN, adminJwt); - userApi.changeRole(userId, UserRole.REGISTERED, adminJwt); - - final String jwtUser = userApi.login("test@test.de", "test"); - final Response res2 = userApi.getProfile(jwtUser); - - assertEquals("REGISTERED", JsonPath.read(res2.readEntity(String.class), "role")); - } - - @Test - public void adminShouldNotMakeHimselfUserIfHeIsOnlyAdmin() { - final Response res1 = userApi.getProfile(adminJwt); - final int userId = JsonPath.read(res1.readEntity(String.class), "id"); - - userApi.changeRole(userId, UserRole.REGISTERED, adminJwt); - - final Response res2 = userApi.getProfile(adminJwt); - assertEquals("ADMIN", JsonPath.read(res2.readEntity(String.class), "role")); - } - - @Test - public void userShouldNotBeAbleToDemoteAnAdmin() { - userApi.create(createUserJson("test@test.de", "test")); - final String jwt = userApi.login("test@test.de", "test"); - - final Response res = userApi.delete(1, jwt); - assertEquals(HttpStatus.FORBIDDEN.value(), res.getStatus()); - } - - @Test - public void shouldFailToLoginWithWrongPassword() { - userApi.create(createUserJson("test@test.de", "test")); - final Response res = userApi.loginRaw("test@test.de", "123"); - - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - assertFalse(res.readEntity(String.class).contains("Bearer: ")); - } - - @Test - public void userShouldNotDeleteAnotherUser() { - userApi.create(createUserJson("test1@test.de", "test")); - final Response res1 = userApi.create(createUserJson("test2@test.de", "test")); - - final int id = JsonPath.read(res1.readEntity(String.class), "id"); - final String jwt = userApi.login("test1@test.de", "test"); - - final Response res = userApi.delete(id, jwt); - - assertEquals(HttpStatus.FORBIDDEN.value(), res.getStatus()); - } - - @Test - public void adminShouldDeleteAUser() { - final Response res1 = userApi.create(createUserJson("test@test.de", "test")); - - final int userId = JsonPath.read(res1.readEntity(String.class), "id"); - - final Response res = userApi.delete(userId, adminJwt); - - assertEquals(HttpStatus.NO_CONTENT.value(), res.getStatus()); - } - - @Test - public void adminShouldNotDeleteHimselfIfHeIsTheOnlyAdmin() { - final Response res = userApi.delete(1, adminJwt); - - assertEquals(HttpStatus.NOT_FOUND.value(), res.getStatus()); - } - - @Test - public void adminShouldDeleteHimselfIfHeIsNotTheOnlyAdmin() { - final Response res1 = userApi.create(createUserJson("admin2@alex.example", "admin"), adminJwt); - - final int id = JsonPath.read(res1.readEntity(String.class), "id"); - userApi.changeRole(id, UserRole.ADMIN, adminJwt); - - final String jwtAdmin2 = userApi.login("admin2@alex.example", "admin"); - - final Response res2 = userApi.delete(id, jwtAdmin2); - assertEquals(HttpStatus.NO_CONTENT.value(), res2.getStatus()); - } - - @Test - public void userShouldNotGetAllUsers() { - userApi.create(createUserJson("test@test.de", "test")); - final String jwt = userApi.login("test@test.de", "test"); - final Response res = userApi.getAll(jwt); - - assertEquals(HttpStatus.FORBIDDEN.value(), res.getStatus()); - } - - @Test - public void adminShouldGetAllUsers() throws Exception { - userApi.create(createUserJson("test1@test.de", "test")); - userApi.create(createUserJson("test2@test.de", "test")); - - final Response res = userApi.getAll(adminJwt); - assertEquals(HttpStatus.OK.value(), res.getStatus()); - - final JsonNode users = objectMapper.readTree(res.readEntity(String.class)); - assertEquals(3, users.size()); - } - - @Test - public void adminShouldDeleteMultipleUsersAtOnce() throws Exception { - final Response res1 = userApi.create(createUserJson("test1@test.de", "test")); - final Response res2 = userApi.create(createUserJson("test2@test.de", "test")); - - final int userId1 = JsonPath.read(res1.readEntity(String.class), "id"); - final int userId2 = JsonPath.read(res2.readEntity(String.class), "id"); - final List userIds = Arrays.asList(userId1, userId2); - - final Response res3 = userApi.delete(userIds, adminJwt); - assertEquals(HttpStatus.NO_CONTENT.value(), res3.getStatus()); - - final Response res4 = userApi.getAll(adminJwt); - assertEquals(1, objectMapper.readTree(res4.readEntity(String.class)).size()); - } - - @Test - public void adminShouldNotDeleteMultipleUsersIfItContainsAnInvalidId() throws Exception { - final Response res1 = userApi.create(createUserJson("test1@test.de", "test")); - final Response res2 = userApi.create(createUserJson("test2@test.de", "test")); - final Response res3 = userApi.getAll(adminJwt); - - final int userId1 = JsonPath.read(res1.readEntity(String.class), "id"); - final int userId2 = JsonPath.read(res2.readEntity(String.class), "id"); - final List userIds = Arrays.asList(userId1, userId2, 10); - - final Response res4 = userApi.delete(userIds, adminJwt); - assertEquals(HttpStatus.NOT_FOUND.value(), res4.getStatus()); - - final Response res5 = userApi.getAll(adminJwt); - - JSONAssert.assertEquals(res3.readEntity(String.class), res5.readEntity(String.class), true); - } - - @Test - public void shouldNotCreateAnonymousUserIfRegistrationIsDisabled() throws Exception { - final Settings settings = settingsApi.get().readEntity(Settings.class); - settings.setAllowUserRegistration(false); - settingsApi.update(settings, adminJwt); - - final Response res1 = userApi.create(createUserJson("test@test.de", "test")); - assertEquals(HttpStatus.FORBIDDEN.value(), res1.getStatus()); - JsonPath.read(res1.readEntity(String.class), "message"); - - shouldNotLoginWith404("test@test.de", "test"); - } - - private void shouldLogin(String email, String password) { - final Response res = userApi.loginRaw(email, password); - assertEquals(HttpStatus.OK.value(), res.getStatus()); - JsonPath.read(res.readEntity(String.class), "token"); - } - - private void shouldNotLoginWith404(String email, String password) { - final Response res = userApi.loginRaw(email, password); - assertEquals(HttpStatus.NOT_FOUND.value(), res.getStatus()); - checkIsRestError(res.readEntity(String.class)); - } - - private void shouldNotLoginWith400(String email, String password) { - final Response res = userApi.loginRaw(email, password); - assertEquals(HttpStatus.BAD_REQUEST.value(), res.getStatus()); - checkIsRestError(res.readEntity(String.class)); - } - - @Test - public void registeredUserShouldNotCreateOtherUsers() throws Exception { - userApi.create(createUserJson("test@test.de", "test")); - final String jwt = userApi.login("test@test.de", "test"); - final Response res = userApi.create(createUserJson("test2@test.de", "test"), jwt); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res.getStatus()); - - shouldNotLoginWith404("test2@test.de", "test"); - } - - @Test - public void shouldChangePassword() throws Exception { - final User user = userApi.create(createUserJson("test@test.de", "test")).readEntity(User.class); - final String jwt = userApi.login(user.getEmail(), "test"); - - final Response res = userApi.changePassword(user.getId(), "test", "new", jwt); - assertEquals(HttpStatus.OK.value(), res.getStatus()); - - shouldNotLoginWith400("test@test.de", "test"); - shouldLogin("test@test.de", "new"); - } - - @Test - public void userShouldNotChangePasswordOfAnotherUser() throws Exception { - final User user1 = userApi.create(createUserJson("test1@test.de", "test")).readEntity(User.class); - final User user2 = userApi.create(createUserJson("test2@test.de", "test")).readEntity(User.class); - - final String jwt = userApi.login(user1.getEmail(), "test"); - - final Response res = userApi.changePassword(user2.getId(), "test", "new", jwt); - assertEquals(HttpStatus.FORBIDDEN.value(), res.getStatus()); - shouldLogin("test2@test.de", "test"); - } - - @Test - public void userShouldNotChangeHisUsername() { - final String user = createUserJson("test@test.de", "test", "test"); - - final Response res1 = userApi.create(user); - final String jwt = userApi.login("test@test.de", "test"); - - final User userPre = res1.readEntity(User.class); - - final Response res2 = userApi.changeUsername(userPre.getId(), "test2", jwt); - assertEquals(HttpStatus.FORBIDDEN.value(), res2.getStatus()); - - final Response res3 = userApi.get(userPre.getId(), jwt); - assertEquals("test", JsonPath.read(res3.readEntity(String.class), "username")); - } - - @Test - public void adminShouldChangeUsername() { - final String user = createUserJson("test@test.de", "test", "test"); - - final Response res1 = userApi.create(user); - final String jwt = userApi.login("test@test.de", "test"); - - final User userPre = res1.readEntity(User.class); - - final Response res2 = userApi.changeUsername(userPre.getId(), "test2", adminJwt); - assertEquals(HttpStatus.OK.value(), res2.getStatus()); - - final Response res3 = userApi.get(userPre.getId(), jwt); - assertEquals("test2", JsonPath.read(res3.readEntity(String.class), "username")); - } - - @Test - public void cannotCreateUserWithoutUsernameAsAnonymousUser() throws Exception { - cannotCreateUser(null); - } - - @Test - public void cannotCreateUserWithoutUsernameAsAdmin() throws Exception { - cannotCreateUser(adminJwt); - } - - @Test - public void cannotCreateUserWithSameUsernameTwice() throws Exception { - final String user1 = createUserJson("test1@test.de", "test", "test"); - final String user2 = createUserJson("test2@test.de", "test", "test"); - - final Response res1 = userApi.create(user1); - assertEquals(HttpStatus.CREATED.value(), res1.getStatus()); - - final String usersPre = userApi.getAll(adminJwt).readEntity(String.class); - - final Response res2 = userApi.create(user2); - assertEquals(HttpStatus.BAD_REQUEST.value(), res2.getStatus()); - - final String usersPost = userApi.getAll(adminJwt).readEntity(String.class); - JSONAssert.assertEquals(usersPre, usersPost, true); - } - - @Test - public void shouldGetTheCurrentProfileAsAdmin() { - final Response res = userApi.getProfile(adminJwt); - final String email = JsonPath.read(res.readEntity(String.class), "email"); - assertEquals(email, ADMIN_EMAIL); - } - - @Test - public void shouldFailToDeleteUsersWhenContainingOwnId() throws Exception { - final Response res1 = userApi.create(createUserJson("test1@test.de", "test")); - final Response res2 = userApi.create(createUserJson("test2@test.de", "test")); - final Response res3 = userApi.getProfile(adminJwt); - - final int adminId = JsonPath.read(res3.readEntity(String.class), "id"); - final int userId1 = JsonPath.read(res1.readEntity(String.class), "id"); - final int userId2 = JsonPath.read(res2.readEntity(String.class), "id"); - final List userIds = Arrays.asList(userId1, userId2, adminId); - - final Response res4 = userApi.delete(userIds, adminJwt); - assertEquals(3, objectMapper.readTree(res4.readEntity(String.class)).size()); - } - - - @ParameterizedTest(name = "search for \"{0}\", expect user \"{1}, {2}\" for the test") - @CsvSource({ - "abc, abc, abc@test.de", - "abc@test.de, abc, abc@test.de", - "def, def, def@test.de", - "def@test.de, def, def@test.de" - }) - public void shouldSearchUserByEmail(String searchValue, String expectedUsername, String expectedEmail) { - userApi.create(createUserJson("abc@test.de", "abc", "test")); - userApi.create(createUserJson("def@test.de", "def", "test")); - - final Response res = userApi.search(searchValue, adminJwt); - assertEquals(HttpStatus.OK.value(), res.getStatus()); - final List users = res.readEntity(new GenericType<>() { - }); - assertEquals(1, users.size()); - assertEquals(expectedUsername, users.get(0).getUsername()); - assertEquals(expectedEmail, users.get(0).getEmail()); - } - - @Test - public void shouldReturnEmptyListForEmptySearchResult() { - createDemoUsers(); - final Response res = userApi.search("unknown", adminJwt); - assertEquals(HttpStatus.OK.value(), res.getStatus()); - final List users = res.readEntity(new GenericType<>() { - }); - assertEquals(0, users.size()); - } - - @Test - public void shouldGetManyUsersByIds() { - final List demoUsers = createDemoUsers(); - final Response res = userApi.getAll(Arrays.asList(demoUsers.get(0).getId(), demoUsers.get(1).getId()), adminJwt); - assertEquals(HttpStatus.OK.value(), res.getStatus()); - final List users = res.readEntity(new GenericType<>() { - }); - assertEquals(2, users.size()); - assertTrue(users.stream().anyMatch(u -> u.getId().equals(demoUsers.get(0).getId()))); - assertTrue(users.stream().anyMatch(u -> u.getId().equals(demoUsers.get(1).getId()))); - } - - @Test - public void shouldFailToGetManyUsersByIdsIfIdIsNotFound() { - final List demoUsers = createDemoUsers(); - final Response res = userApi.getAll(Arrays.asList(demoUsers.get(0).getId(), -1L), adminJwt); - assertEquals(HttpStatus.NOT_FOUND.value(), res.getStatus()); - res.readEntity(SpringRestError.class); - } - - private void cannotCreateUser(String jwt) throws Exception { - final String user = "{\"email\":\"test@test.de\",\"password\":\"test\"}"; - - final String usersPre = userApi.getAll(adminJwt).readEntity(String.class); - - final Response res = jwt == null ? userApi.create(user) : userApi.create(user, jwt); - assertEquals(HttpStatus.UNAUTHORIZED.value(), res.getStatus()); - - final String usersPost = userApi.getAll(adminJwt).readEntity(String.class); - JSONAssert.assertEquals(usersPre, usersPost, true); - } - - private String createUserJson(String email, String password) { - return "{" - + "\"username\":\"" + email.split("@")[0] + "\"" - + ",\"email\":\"" + email + "\"" - + ",\"password\":\"" + password + "\"" - + "}"; - } - - private String createUserJson(String email, String username, String password) { - return "{" - + "\"username\":\"" + username + "\"" - + ",\"email\":\"" + email + "\"" - + ",\"password\":\"" + password + "\"" - + "}"; - } - - private List createDemoUsers() { - final User user1 = userApi.create(createUserJson("user1@test.de", "user1", "test")) - .readEntity(User.class); - final User user2 = userApi.create(createUserJson("user2@test.de", "user2", "test")) - .readEntity(User.class); - final User user3 = userApi.create(createUserJson("user3@test.de", "user3", "test")) - .readEntity(User.class); - - return Arrays.asList(user1, user2, user3); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/WebhookResourceIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/WebhookResourceIT.java deleted file mode 100644 index 25cada7da..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/WebhookResourceIT.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; - -import com.jayway.jsonpath.JsonPath; -import de.learnlib.alex.integrationtests.resources.api.UserApi; -import de.learnlib.alex.integrationtests.resources.api.WebhookApi; -import de.learnlib.alex.webhooks.entities.Webhook; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; -import javax.ws.rs.core.GenericType; -import javax.ws.rs.core.Response; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.skyscreamer.jsonassert.JSONAssert; -import org.springframework.http.HttpStatus; - -public class WebhookResourceIT extends AbstractResourceIT { - - private String jwtUser1; - - private String jwtUser2; - - private UserApi userApi; - - private WebhookApi webhookApi; - - @BeforeEach - public void pre() { - userApi = new UserApi(client, port); - webhookApi = new WebhookApi(client, port); - - userApi.create("{\"email\":\"test1@test.de\",\"username\":\"test1\",\"password\":\"test\"}"); - userApi.create("{\"email\":\"test2@test.de\",\"username\":\"test2\",\"password\":\"test\"}"); - - jwtUser1 = userApi.login("test1@test.de", "test"); - jwtUser2 = userApi.login("test2@test.de", "test"); - } - - @Test - public void shouldCreateAWebhook() { - final String wh = createWebhookJson("test", "http://test/", Arrays.asList("PROJECT_CREATED", "PROJECT_DELETED")); - final Response res1 = webhookApi.create(wh, jwtUser1); - - assertEquals(HttpStatus.OK.value(), res1.getStatus()); - JsonPath.read(res1.readEntity(String.class), "$.id"); - } - - @Test - public void shouldNotCreateAWebhookWithTheSameUrlTwice() throws Exception { - final String wh1 = createWebhookJson("test", "http://test/", Arrays.asList("PROJECT_CREATED", "PROJECT_DELETED")); - final String wh2 = createWebhookJson("test", "http://test/", Arrays.asList("PROJECT_CREATED", "PROJECT_DELETED")); - webhookApi.create(wh1, jwtUser1); - final Response res2 = webhookApi.create(wh2, jwtUser1); - - assertEquals(HttpStatus.BAD_REQUEST.value(), res2.getStatus()); - assertEquals(1, getNumberOfWebhooks(jwtUser1)); - } - - @Test - public void shouldNotCreateWebhookWithEmptyEventList() throws Exception { - final String wh1 = createWebhookJson("test", "http://test/", new ArrayList<>()); - final Response res1 = webhookApi.create(wh1, jwtUser1); - - assertEquals(HttpStatus.BAD_REQUEST.value(), res1.getStatus()); - assertEquals(0, getNumberOfWebhooks(jwtUser1)); - } - - @Test - public void shouldUpdateWebhook() throws Exception { - final String wh1 = createWebhookJson("test", "http://test/", Collections.singletonList("PROJECT_CREATED")); - final Response res1 = webhookApi.create(wh1, jwtUser1); - - final Webhook webhook = res1.readEntity(Webhook.class); - webhook.setName("updatedName"); - webhook.setUrl("http://test2/"); - - final Response res2 = webhookApi.update(webhook.getId().intValue(), objectMapper.writeValueAsString(webhook), jwtUser1); - - assertEquals(Response.Status.OK.getStatusCode(), res2.getStatus()); - JSONAssert.assertEquals(objectMapper.writeValueAsString(webhook), res2.readEntity(String.class), true); - } - - @Test - public void shouldFailToUpdateWebhookIfEventsAreEmpty() throws Exception { - final String wh1 = createWebhookJson("test", "http://test/", Collections.singletonList("PROJECT_CREATED")); - final Response res1 = webhookApi.create(wh1, jwtUser1); - - final Webhook webhook = res1.readEntity(Webhook.class); - webhook.getEvents().clear(); - - final Response res2 = webhookApi.update(webhook.getId().intValue(), objectMapper.writeValueAsString(webhook), jwtUser1); - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), res2.getStatus()); - } - - @Test - public void shouldFailToUpdateWebhookIfUrlExists() throws Exception { - webhookApi.create(createWebhookJson("test", "http://exists/", Collections.singletonList("PROJECT_CREATED")), jwtUser1); - final String wh1 = createWebhookJson("test", "http://test/", Collections.singletonList("PROJECT_CREATED")); - final Response res1 = webhookApi.create(wh1, jwtUser1); - - final Webhook webhook = res1.readEntity(Webhook.class); - webhook.setUrl("http://exists/"); - - final Response res2 = webhookApi.update(webhook.getId().intValue(), objectMapper.writeValueAsString(webhook), jwtUser1); - assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), res2.getStatus()); - } - - @Test - public void shouldDeleteAWebhook() throws Exception { - final String wh1 = createWebhookJson("test", "http://test/", Arrays.asList("PROJECT_CREATED", "PROJECT_DELETED")); - final Response res1 = webhookApi.create(wh1, jwtUser1); - final Integer id = JsonPath.read(res1.readEntity(String.class), "id"); - final Response res2 = webhookApi.delete(id, jwtUser1); - - assertEquals(HttpStatus.NO_CONTENT.value(), res2.getStatus()); - assertEquals(0, getNumberOfWebhooks(jwtUser1)); - } - - @Test - public void shouldDeleteWebhooks() throws Exception { - final String wh1 = createWebhookJson("test", "http://test/", Arrays.asList("PROJECT_CREATED", "PROJECT_DELETED")); - final Response res1 = webhookApi.create(wh1, jwtUser1); - final Integer id1 = JsonPath.read(res1.readEntity(String.class), "id"); - - final String wh2 = createWebhookJson("test2", "http://test2/", Arrays.asList("PROJECT_CREATED", "PROJECT_DELETED")); - final Response res2 = webhookApi.create(wh2, jwtUser1); - final Integer id2 = JsonPath.read(res2.readEntity(String.class), "id"); - - final Response res3 = webhookApi.delete(Arrays.asList(id1, id2), jwtUser1); - assertEquals(HttpStatus.NO_CONTENT.value(), res3.getStatus()); - assertEquals(0, getNumberOfWebhooks(jwtUser1)); - } - - @Test - public void shouldFailToDeleteWebhooksIfOneDoesNotExist() throws Exception { - final String wh1 = createWebhookJson("test", "http://test1/", Arrays.asList("PROJECT_CREATED", "PROJECT_DELETED")); - final Response res1 = webhookApi.create(wh1, jwtUser1); - final int id1 = JsonPath.read(res1.readEntity(String.class), "$.id"); - - final Response res3 = webhookApi.delete(Arrays.asList(id1, -1), jwtUser1); - assertEquals(Response.Status.NOT_FOUND.getStatusCode(), res3.getStatus()); - assertEquals(1, getNumberOfWebhooks(jwtUser1)); - } - - @Test - public void shouldNotDeleteAWebhookOfAnotherUser() throws Exception { - final String wh = createWebhookJson("test", "http://test/", Arrays.asList("PROJECT_CREATED", "PROJECT_DELETED")); - final Response res1 = webhookApi.create(wh, jwtUser2); - final Integer id = JsonPath.read(res1.readEntity(String.class), "id"); - - final Response res2 = webhookApi.delete(id, jwtUser1); - - assertEquals(HttpStatus.UNAUTHORIZED.value(), res2.getStatus()); - assertEquals(1, getNumberOfWebhooks(jwtUser2)); - } - - @Test - public void shouldFailToDeleteAnUnknownWebhook() throws Exception { - final String wh1 = createWebhookJson("test", "http://test/", Arrays.asList("PROJECT_CREATED", "PROJECT_DELETED")); - webhookApi.create(wh1, jwtUser1); - final String wh2 = createWebhookJson("test", "http://test/", Arrays.asList("PROJECT_CREATED", "PROJECT_DELETED")); - webhookApi.create(wh2, jwtUser2); - - final Response res = webhookApi.delete(-1, jwtUser1); - assertEquals(HttpStatus.NOT_FOUND.value(), res.getStatus()); - assertEquals(1, getNumberOfWebhooks(jwtUser1)); - assertEquals(1, getNumberOfWebhooks(jwtUser2)); - } - - @Test - public void shouldGetAllEvents() { - final Response res = webhookApi.getEvents(jwtUser1); - final List events = res.readEntity(new GenericType<>() { - }); - assertFalse(events.isEmpty()); - } - - private int getNumberOfWebhooks(String jwt) throws Exception { - final Response res = webhookApi.get(jwt); - return objectMapper.readTree(res.readEntity(String.class)).size(); - } - - private String createWebhookJson(String name, String url, List events) { - events = events.stream().map(e -> "\"" + e + "\"").collect(Collectors.toList()); - return "{" - + "\"name\":\"" + name + "\"" - + ",\"url\":\"" + url + "\"" - + ",\"events\":[" + String.join(",", events) + "]" - + ",\"method\":\"POST\"" - + "}"; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/AbstractApi.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/AbstractApi.java deleted file mode 100644 index 22c7f2adf..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/AbstractApi.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources.api; - -import com.fasterxml.jackson.databind.ObjectMapper; -import javax.ws.rs.client.Client; - -public abstract class AbstractApi { - - protected final Client client; - - protected final ObjectMapper objectMapper; - - protected final int port; - - protected AbstractApi(Client client, int port) { - this.client = client; - this.port = port; - this.objectMapper = new ObjectMapper(); - } - - protected String baseUrl() { - return "http://localhost/" + port + "/rest"; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/CounterApi.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/CounterApi.java deleted file mode 100644 index 58abc436a..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/CounterApi.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources.api; - -import de.learnlib.alex.data.entities.Counter; -import java.util.List; -import java.util.stream.Collectors; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -public class CounterApi extends AbstractApi { - - public CounterApi(Client client, int port) { - super(client, port); - } - - public Response getAll(Long projectId, String jwt) { - return client.target(url(http://github.com/projectId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response create(Long projectId, Counter counter, String jwt) { - return client.target(url(http://github.com/projectId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .post(Entity.json(counter)); - } - - public Response update(Long projectId, Long counterId, Counter counter, String jwt) { - return client.target(url(http://github.com/projectId) + "/" + counterId).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .put(Entity.json(counter)); - } - - public Response delete(Long projectId, Counter counter, String jwt) { - return client.target(url(http://github.com/projectId,%20counter.getId())).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .delete(); - } - - public Response delete(Long projectId, List counters, String jwt) { - final List ids = counters.stream() - .map(c -> String.valueOf(c.getId())) - .collect(Collectors.toList()); - - return client.target(url(http://github.com/projectId) + "/batch/" + String.join(",", ids)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .delete(); - } - - public String url(http://github.com/Long%20projectId) { - return baseUrl() + "/projects/" + projectId + "/counters"; - } - - public String url(http://github.com/Long%20projectId,%20Long%20counterId) { - return url(http://github.com/projectId) + "/" + counterId; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/LearnerApi.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/LearnerApi.java deleted file mode 100644 index e05f7a5fb..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/LearnerApi.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources.api; - -import de.learnlib.alex.learning.entities.LearnerResumeConfiguration; -import de.learnlib.alex.learning.entities.LearnerStartConfiguration; -import de.learnlib.alex.learning.entities.ReadOutputConfig; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.Response; - -public class LearnerApi extends AbstractApi { - - public LearnerApi(Client client, int port) { - super(client, port); - } - - public Response start(Long projectId, LearnerStartConfiguration configuration, String jwt) { - return client.target(url(http://github.com/projectId) + "/start").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .post(Entity.json(configuration)); - } - - public Response resume(Long projectId, Long testNo, LearnerResumeConfiguration configuration, String jwt) { - return client.target(url(http://github.com/projectId) + "/" + testNo + "/resume").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .post(Entity.json(configuration)); - } - - public Response abort(Long projectId, Long resultId, String jwt) { - return client.target(url(http://github.com/projectId) + "/stop").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .post(Entity.json("{\"projectId\": " + projectId + ", \"resultId\": " + resultId + "}")); - } - - public Response getStatus(Long projectId, String jwt) { - return client.target(url(http://github.com/projectId) + "/status").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .get(); - } - - public Response readOutput(Long projectId, ReadOutputConfig config, String jwt) { - return client.target(url(http://github.com/projectId) + "/outputs").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .post(Entity.json(config)); - } - - private String url(http://github.com/Long%20projectId) { - return baseUrl() + "/projects/" + projectId + "/learner"; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/LearnerResultApi.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/LearnerResultApi.java deleted file mode 100644 index 45912857b..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/LearnerResultApi.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources.api; - -import javax.ws.rs.client.Client; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -public class LearnerResultApi extends AbstractApi { - - public LearnerResultApi(Client client, int port) { - super(client, port); - } - - public Response get(Long projectId, Long testNo, String jwt) { - return client.target(url(http://github.com/projectId,%20testNo)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response getAll(Long projectId, String jwt) { - return client.target(url(http://github.com/projectId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - private String url(http://github.com/Long%20projectId) { - return baseUrl() + "/projects/" + projectId + "/results"; - } - - private String url(http://github.com/Long%20projectId,%20Long%20testNo) { - return url(http://github.com/projectId) + "/" + testNo; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/LearnerSetupApi.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/LearnerSetupApi.java deleted file mode 100644 index 9a905c1f2..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/LearnerSetupApi.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources.api; - -import de.learnlib.alex.learning.entities.LearnerOptions; -import de.learnlib.alex.learning.entities.LearnerSetup; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -public class LearnerSetupApi extends AbstractApi { - - public LearnerSetupApi(Client client, int port) { - super(client, port); - } - - public Response getAll(Long projectId, String jwt) { - return client.target(url(http://github.com/projectId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response get(Long projectId, Long setupId, String jwt) { - return client.target(url(http://github.com/projectId,%20setupId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response create(Long projectId, LearnerSetup setup, String jwt) { - return client.target(url(http://github.com/projectId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .post(Entity.json(setup)); - } - - public Response run(Long projectId, Long setupId, String jwt) { - return client.target(url(http://github.com/projectId,%20setupId) + "/run").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .post(Entity.json("")); - } - - public Response run(Long projectId, Long setupId, LearnerOptions options, String jwt) { - return client.target(url(http://github.com/projectId,%20setupId) + "/run").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .post(Entity.json(options)); - } - - public Response update(Long projectId, Long setupId, LearnerSetup setup, String jwt) { - return client.target(url(http://github.com/projectId,%20setupId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .put(Entity.json(setup)); - } - - public Response delete(Long projectId, Long setupId, String jwt) { - return client.target(url(http://github.com/projectId,%20setupId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .delete(); - } - - public Response copy(Long projectId, Long setupId, String jwt) { - return client.target(url(http://github.com/projectId,%20setupId) + "/copy").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .post(Entity.json("{}")); - } - - private String url(http://github.com/Long%20projectId) { - return baseUrl() + "/projects/" + projectId + "/learner/setups"; - } - - private String url(http://github.com/Long%20projectId,%20Long%20setupId) { - return baseUrl() + "/projects/" + projectId + "/learner/setups/" + setupId; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/LtsFormulaApi.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/LtsFormulaApi.java deleted file mode 100644 index 40caf0d62..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/LtsFormulaApi.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources.api; - -import de.learnlib.alex.modelchecking.entities.LtsFormula; -import de.learnlib.alex.modelchecking.entities.LtsFormulaSuite; -import java.util.List; -import java.util.stream.Collectors; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -public class LtsFormulaApi extends AbstractApi { - - public LtsFormulaApi(Client client, int port) { - super(client, port); - } - - public Response create(Long projectId, Long suiteId, LtsFormula formula, String jwt) { - return client.target(url(http://github.com/projectId,%20suiteId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .post(Entity.json(formula)); - } - - public Response update(Long projectId, Long suiteId, Long formulaId, LtsFormula formula, String jwt) { - return client.target(url(http://github.com/projectId,%20suiteId,%20formulaId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .put(Entity.json(formula)); - } - - public Response delete(Long projectId, Long suiteId, Long formulaId, String jwt) { - return client.target(url(http://github.com/projectId,%20suiteId,%20formulaId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .delete(); - } - - public Response delete(Long projectId, Long suiteId, List formulaIds, String jwt) { - return client.target(url(http://github.com/projectId,%20suiteId,%20formulaIds)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .delete(); - } - - public Response updateSuite(Long projectId, Long suiteId, Long formulaId, LtsFormulaSuite suite, String jwt) { - return client.target(url(http://github.com/projectId,%20suiteId,%20formulaId) + "/suite").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .put(Entity.json(suite)); - } - - public Response updateSuite(Long projectId, Long suiteId, List formulaIds, LtsFormulaSuite suite, String jwt) { - return client.target(url(http://github.com/projectId,%20suiteId,%20formulaIds) + "/suite").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .put(Entity.json(suite)); - } - - private String url(http://github.com/Long%20projectId,%20Long%20suiteId) { - return baseUrl() + "/projects/" + projectId + "/ltsFormulaSuites/" + suiteId + "/ltsFormulas"; - } - - private String url(http://github.com/Long%20projectId,%20Long%20suiteId,%20Long%20formulaId) { - return url(http://github.com/projectId,%20suiteId) + "/" + formulaId; - } - - private String url(http://github.com/Long%20projectId,%20Long%20suiteId,%20List%3CLong%3E%20formulaIds) { - final List ids = formulaIds.stream().map(String::valueOf).collect(Collectors.toList()); - return url(http://github.com/projectId,%20suiteId) + "/batch/" + String.join(",", ids); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/LtsFormulaSuiteApi.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/LtsFormulaSuiteApi.java deleted file mode 100644 index 411ad4333..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/LtsFormulaSuiteApi.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources.api; - -import de.learnlib.alex.modelchecking.entities.LtsFormulaSuite; -import java.util.List; -import java.util.stream.Collectors; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -public class LtsFormulaSuiteApi extends AbstractApi { - - public LtsFormulaSuiteApi(Client client, int port) { - super(client, port); - } - - public Response create(Long projectId, LtsFormulaSuite suite, String jwt) { - return client.target(url(http://github.com/projectId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .post(Entity.json(suite)); - } - - public Response getAll(Long projectId, String jwt) { - return client.target(url(http://github.com/projectId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response get(Long projectId, Long suiteId, String jwt) { - return client.target(url(http://github.com/projectId,%20suiteId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response delete(Long projectId, Long suiteId, String jwt) { - return client.target(url(http://github.com/projectId,%20suiteId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .delete(); - } - - public Response deleteAll(Long projectId, List suiteIds, String jwt) { - final String ids = suiteIds.stream() - .map(String::valueOf) - .collect(Collectors.joining(",")); - - return client.target(url(http://github.com/projectId) + "/batch/" + ids).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .delete(); - } - - public Response update(Long projectId, Long suiteId, LtsFormulaSuite suite, String jwt) { - return client.target(url(http://github.com/projectId,%20suiteId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .put(Entity.json(suite)); - } - - private String url(http://github.com/Long%20projectId) { - return baseUrl() + "/projects/" + projectId + "/ltsFormulaSuites"; - } - - private String url(http://github.com/Long%20projectId,%20Long%20suiteId) { - return baseUrl() + "/projects/" + projectId + "/ltsFormulaSuites/" + suiteId; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/ProjectApi.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/ProjectApi.java deleted file mode 100644 index 4c76964aa..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/ProjectApi.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources.api; - -import java.util.List; -import java.util.stream.Collectors; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -public class ProjectApi extends AbstractApi { - - public ProjectApi(Client client, int port) { - super(client, port); - } - - public Response create(String project, String jwt) { - return client.target(url()).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .post(Entity.json(project)); - } - - public Response importProject(String project, String jwt) { - return client.target(url() + "/import").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .post(Entity.json(project)); - } - - public Response getAll(String jwt) { - return client.target(url()).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response get(Long projectId, String jwt) { - return client.target(url() + "/" + projectId).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response update(Long projectId, String project, String jwt) { - return client.target(url() + "/" + projectId).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .put(Entity.json(project)); - } - - public Response delete(Long projectId, String jwt) { - return client.target(url() + "/" + projectId).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .delete(); - } - - public Response delete(List projectIds, String jwt) { - return client.target(url() + "/batch/" + String.join(",", projectIds)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .delete(); - } - - public Response addOwners(Long projectId, List ownerIds, String jwt) { - return client.target(url() + "/" + projectId + "/owners").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .post(Entity.json(ownerIds)); - } - - public Response addMembers(Long projectId, List memberIds, String jwt) { - return client.target(url() + "/" + projectId + "/members").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .post(Entity.json(memberIds)); - } - - public Response removeMembers(Long projectId, List memberIds, String jwt) { - final String ids = memberIds.stream() - .map(String::valueOf) - .collect(Collectors.joining(",")); - - return client.target(url() + "/" + projectId + "/members/" + ids).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .delete(); - } - - public Response removeOwners(Long projectId, List ownerIds, String jwt) { - final String ids = ownerIds.stream() - .map(String::valueOf) - .collect(Collectors.joining(",")); - - return client.target(url() + "/" + projectId + "/owners/" + ids).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .delete(); - } - - public String url() { - return baseUrl() + "/projects"; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/ProjectEnvironmentApi.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/ProjectEnvironmentApi.java deleted file mode 100644 index b35ed25ae..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/ProjectEnvironmentApi.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources.api; - -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.data.entities.ProjectEnvironmentVariable; -import de.learnlib.alex.data.entities.ProjectUrl; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -public class ProjectEnvironmentApi extends AbstractApi { - - public ProjectEnvironmentApi(Client client, int port) { - super(client, port); - } - - public Response getAll(Long projectId, String jwt) { - return client.target(envUrl(projectId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response create(Long projectId, ProjectEnvironment env, String jwt) { - return client.target(envUrl(projectId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .post(Entity.json(env)); - } - - public Response delete(Long projectId, Long envId, String jwt) { - return client.target(envUrl(projectId, envId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .delete(); - } - - public Response update(Long projectId, Long envId, ProjectEnvironment env, String jwt) { - return client.target(envUrl(projectId, envId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .put(Entity.json(env)); - } - - public Response createUrl(Long projectId, Long envId, ProjectUrl projectUrl, String jwt) { - return client.target(envUrlUrl(projectId, envId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .post(Entity.json(projectUrl)); - } - - public Response updateUrl(Long projectId, Long envId, Long urlId, ProjectUrl projectUrl, String jwt) { - return client.target(envUrlUrl(projectId, envId, urlId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .put(Entity.json(projectUrl)); - } - - public Response deleteUrl(Long projectId, Long envId, Long urlId, String jwt) { - return client.target(envUrlUrl(projectId, envId, urlId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .delete(); - } - - public Response createVariable(Long projectId, Long envId, ProjectEnvironmentVariable variable, String jwt) { - return client.target(envVarUrl(projectId, envId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .post(Entity.json(variable)); - } - - public Response updateVariable(Long projectId, Long envId, Long varId, ProjectEnvironmentVariable variable, String jwt) { - return client.target(envVarUrl(projectId, envId, varId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .put(Entity.json(variable)); - } - - public Response deleteVariable(Long projectId, Long envId, Long varId, String jwt) { - return client.target(envVarUrl(projectId, envId, varId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .delete(); - } - - private String envUrl(Long projectId) { - return baseUrl() + "/projects/" + projectId + "/environments"; - } - - private String envUrl(Long projectId, Long envId) { - return envUrl(projectId) + "/" + envId; - } - - private String envUrlUrl(Long projectId, Long envId) { - return envUrl(projectId, envId) + "/urls"; - } - - private String envUrlUrl(Long projectId, Long envId, Long urlId) { - return envUrlUrl(projectId, envId) + "/" + urlId; - } - - private String envVarUrl(Long projectId, Long envId) { - return envUrl(projectId, envId) + "/variables"; - } - - private String envVarUrl(Long projectId, Long envId, Long varId) { - return envVarUrl(projectId, envId) + "/" + varId; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/SettingsApi.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/SettingsApi.java deleted file mode 100644 index 0639579c4..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/SettingsApi.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources.api; - -import de.learnlib.alex.settings.entities.Settings; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -public class SettingsApi extends AbstractApi { - - public SettingsApi(Client client, int port) { - super(client, port); - } - - public Response get() { - return client.target(url()).request() - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response get(String jwt) { - return client.target(url()).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response update(Settings settings) throws Exception { - return client.target(url()).request() - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .put(Entity.json(objectMapper.writeValueAsString(settings))); - } - - public Response update(Settings settings, String jwt) throws Exception { - return client.target(url()).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .put(Entity.json(objectMapper.writeValueAsString(settings))); - } - - public String url() { - return baseUrl() + "/settings"; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/SymbolApi.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/SymbolApi.java deleted file mode 100644 index 83e4f48ef..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/SymbolApi.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources.api; - -import java.util.List; -import java.util.stream.Collectors; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -public class SymbolApi extends AbstractApi { - - public SymbolApi(Client client, int port) { - super(client, port); - } - - public Response get(int projectId, Long symbolId, String jwt) { - return client.target(url(http://github.com/projectId,%20symbolId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response update(int projectId, Long symbolId, String symbol, String jwt) { - return client.target(url(http://github.com/projectId,%20symbolId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .put(Entity.json(symbol)); - } - - public Response move(int projectId, Long symbolId, Long groupId, String jwt) { - return client.target(url(http://github.com/projectId,%20symbolId) + "/moveTo/" + groupId).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .put(Entity.json("{}")); - } - - public Response move(int projectId, List symbolIds, Long groupId, String jwt) { - final String ids = symbolIds.stream().map(String::valueOf).collect(Collectors.joining(",")); - - return client.target(url(http://github.com/projectId) + "/batch/" + ids + "/moveTo/" + groupId).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .put(Entity.json("{}")); - } - - public Response get(int projectId, List symbolIds, String jwt) { - final String ids = symbolIds.stream().map(String::valueOf).collect(Collectors.joining(",")); - - return client.target(url(http://github.com/projectId) + "/batch/" + ids).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response getAll(int projectId, String jwt) { - return client.target(url(http://github.com/projectId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response create(int projectId, String symbol, String jwt) { - return client.target(url(http://github.com/projectId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .post(Entity.json(symbol)); - } - - public Response createMany(int projectId, String symbols, String jwt) { - return client.target(url(http://github.com/projectId) + "/batch").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .post(Entity.json(symbols)); - } - - public Response archive(int projectId, int symbolId, String jwt) { - return client.target(url(http://github.com/projectId) + "/" + symbolId + "/hide").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .post(null); - } - - public Response archiveMany(int projectId, List symbolIds, String jwt) { - final String ids = symbolIds.stream().map(String::valueOf).collect(Collectors.joining(",")); - - return client.target(url(http://github.com/projectId) + "/batch/" + ids + "/hide").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .post(null); - } - - public Response restore(Long projectId, Long symbolId, String jwt) { - return client.target(url(http://github.com/projectId) + "/" + symbolId + "/show").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .post(null); - } - - public Response restore(Long projectId, List symbolIds, String jwt) { - final String ids = symbolIds.stream().map(String::valueOf).collect(Collectors.joining(",")); - - return client.target(url(http://github.com/projectId) + "/batch/" + ids + "/show").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .post(null); - } - - public Response delete(int projectId, Long symbolId, String jwt) { - return client.target(url(http://github.com/projectId,%20symbolId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .delete(); - } - - public Response delete(int projectId, List symbolIds, String jwt) { - final String ids = symbolIds.stream().map(String::valueOf).collect(Collectors.joining(",")); - - return client.target(url(http://github.com/projectId) + "/batch/" + ids).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .delete(); - } - - public String url(http://github.com/long%20projectId) { - return baseUrl() + "/projects/" + projectId + "/symbols"; - } - - public String url(http://github.com/long%20projectId,%20long%20symbolId) { - return baseUrl() + "/projects/" + projectId + "/symbols/" + symbolId; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/SymbolGroupApi.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/SymbolGroupApi.java deleted file mode 100644 index f50d894e2..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/SymbolGroupApi.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources.api; - -import de.learnlib.alex.data.entities.SymbolGroup; -import java.util.List; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -public class SymbolGroupApi extends AbstractApi { - - public SymbolGroupApi(Client client, int port) { - super(client, port); - } - - public Response getAll(int projectId, String jwt) { - return client.target(url(http://github.com/projectId) + "?embed=all").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response get(Long projectId, Long groupId, String jwt) { - return client.target(url(http://github.com/projectId.intValue(), groupId.intValue())).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response create(int projectId, String group, String jwt) { - return client.target(url(http://github.com/projectId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .post(Entity.json(group)); - } - - public Response create(int projectId, List groups, String jwt) { - return client.target(url(http://github.com/projectId) + "/batch").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .post(Entity.json(groups)); - } - - public Response update(int projectId, int groupId, String group, String jwt) { - return client.target(url(http://github.com/projectId) + "/" + groupId).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .put(Entity.json(group)); - } - - public Response move(int projectId, int groupId, String group, String jwt) { - return client.target(url(http://github.com/projectId) + "/" + groupId + "/move").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .put(Entity.json(group)); - } - - public Response delete(int projectId, int groupId, String jwt) { - return client.target(url(http://github.com/projectId) + "/" + groupId).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .delete(); - } - - public String url(http://github.com/int%20projectId) { - return baseUrl() + "/projects/" + projectId + "/groups"; - } - - public String url(http://github.com/int%20projectId,%20int%20groupId) { - return url(http://github.com/projectId) + "/" + groupId; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/SymbolParameterApi.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/SymbolParameterApi.java deleted file mode 100644 index 16f06f6a7..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/SymbolParameterApi.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources.api; - -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -public class SymbolParameterApi extends AbstractApi { - - public SymbolParameterApi(Client client, int port) { - super(client, port); - } - - public Response create(int projectId, int symbolId, String parameter, String jwt) { - return client.target(url(http://github.com/projectId,%20symbolId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .post(Entity.json(parameter)); - } - - public Response update(int projectId, int symbolId, int parameterId, String parameter, String jwt) { - return client.target(url(http://github.com/projectId,%20symbolId) + "/" + parameterId).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .put(Entity.json(parameter)); - } - - public Response delete(int projectId, int symbolId, int parameterId, String jwt) { - return client.target(url(http://github.com/projectId,%20symbolId) + "/" + parameterId).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .delete(); - } - - public String url(http://github.com/int%20projectId,%20int%20symbolId) { - return baseUrl() + "/projects/" + projectId + "/symbols/" + symbolId + "/parameters"; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/TestApi.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/TestApi.java deleted file mode 100644 index b0b0b915e..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/TestApi.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources.api; - -import com.fasterxml.jackson.core.JsonProcessingException; -import de.learnlib.alex.testing.entities.TestExecutionConfig; -import java.util.List; -import java.util.stream.Collectors; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -public class TestApi extends AbstractApi { - - public TestApi(Client client, int port) { - super(client, port); - } - - public Response create(int projectId, String test, String jwt) { - return client.target(url(http://github.com/projectId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .post(Entity.json(test)); - } - - public Response createMany(int projectId, String tests, String jwt) { - return client.target(url(http://github.com/projectId) + "/batch").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .post(Entity.json(tests)); - } - - public Response get(int projectId, int testId, String jwt) { - return client.target(url(http://github.com/projectId) + "/" + testId).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response getRoot(int projectId, String jwt) { - return client.target(url(http://github.com/projectId) + "/root").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response update(Long projectId, Long testId, String test, String jwt) { - return client.target(url(http://github.com/projectId) + "/" + testId).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .put(Entity.json(test)); - } - - public Response move(int projectId, int fromTestId, int toTestId, String jwt) { - return client.target(url(http://github.com/projectId) + "/batch/" + fromTestId + "/moveTo/" + toTestId).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .put(Entity.json("")); - } - - public Response delete(int projectId, int testId, String jwt) { - return client.target(url(http://github.com/projectId) + "/" + testId).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .delete(); - } - - public Response deleteMany(int projectId, List testIds, String jwt) { - final List ids = testIds.stream().map(String::valueOf).collect(Collectors.toList()); - return client.target(url(http://github.com/projectId) + "/batch/" + String.join(",", ids)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .delete(); - } - - public Response execute(Long projectId, TestExecutionConfig config, String jwt) throws JsonProcessingException { - return client.target(url(http://github.com/projectId) + "/execute").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .post(Entity.json(objectMapper.writeValueAsString(config))); - } - - public String url(http://github.com/long%20projectId) { - return baseUrl() + "/projects/" + projectId + "/tests"; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/TestExecutionConfigApi.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/TestExecutionConfigApi.java deleted file mode 100644 index 1542b6590..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/TestExecutionConfigApi.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources.api; - -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -public class TestExecutionConfigApi extends AbstractApi { - - public TestExecutionConfigApi(Client client, int port) { - super(client, port); - } - - public Response getAll(int projectId, String jwt) { - return client.target(url(http://github.com/projectId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response create(int projectId, String config, String jwt) { - return client.target(url(http://github.com/projectId)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .post(Entity.json(config)); - } - - public Response delete(int projectId, int configId, String jwt) { - return client.target(url(http://github.com/projectId) + "/" + configId).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .delete(); - } - - public String url(http://github.com/int%20projectId) { - return baseUrl() + "/projects/" + projectId + "/testConfigs"; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/TestReportApi.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/TestReportApi.java deleted file mode 100644 index b237fc922..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/TestReportApi.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources.api; - -import javax.ws.rs.client.Client; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -public class TestReportApi extends AbstractApi { - - public TestReportApi(Client client, int port) { - super(client, port); - } - - public Response get(Long projectId, Long reportId, String jwt) { - return client.target(url(http://github.com/projectId) + "/" + reportId).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public String url(http://github.com/Long%20projectId) { - return baseUrl() + "/projects/" + projectId + "/tests/reports"; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/UserApi.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/UserApi.java deleted file mode 100644 index c243dcece..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/UserApi.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.resources.api; - -import com.jayway.jsonpath.JsonPath; -import de.learnlib.alex.auth.entities.UserRole; -import java.util.List; -import java.util.stream.Collectors; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -public class UserApi extends AbstractApi { - - public UserApi(Client client, int port) { - super(client, port); - } - - public Response create(String user) { - return client.target(url()).request() - .post(Entity.json(user)); - } - - public Response changePassword(Long userId, String oldPassword, String newPassword, String jwt) { - return client.target(url() + "/" + userId + "/password").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .put(Entity.json("{\"oldPassword\": \"" + oldPassword + "\", \"newPassword\":\"" + newPassword + "\"}")); - } - - public Response changeUsername(Long userId, String username, String jwt) { - return client.target(url() + "/" + userId + "/username").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .put(Entity.json("{\"username\": \"" + username + "\"}")); - } - - public String login(String email, String password) { - final Response res = client.target(url() + "/login").request() - .post(Entity.json("{\"email\":\"" + email + "\",\"password\":\"" + password + "\"}")); - - return "Bearer " + JsonPath.read(res.readEntity(String.class), "token"); - } - - public Response loginRaw(String email, String password) { - return client.target(url() + "/login").request() - .post(Entity.json("{\"email\":\"" + email + "\",\"password\":\"" + password + "\"}")); - } - - public Response getProfile(String jwt) { - return client.target(url() + "/myself").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .get(); - } - - public Response create(String user, String jwt) { - return client.target(url()).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .post(Entity.json(user)); - } - - public Response getAll(String jwt) { - return client.target(url()).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response getAll(List userIds, String jwt) { - final String ids = userIds.stream() - .map(String::valueOf) - .collect(Collectors.joining(",")); - - return client.target(url() + "/batch/" + ids).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response get(Long id, String jwt) { - return client.target(url() + "/" + id).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response delete(int userId, String jwt) { - return client.target(url() + "/" + userId).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .delete(); - } - - public Response delete(List userIds, String jwt) { - final List ids = userIds.stream().map(String::valueOf).collect(Collectors.toList()); - return client.target(url() + "/batch/" + String.join(",", ids)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .delete(); - } - - public Response search(String value, String jwt) { - return client.target(url() + "/search?searchterm=" + value).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON) - .get(); - } - - public Response changeRole(int userId, UserRole role, String jwt) { - return client.target(url() + "/" + userId + "/role").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .put(Entity.json("{\"role\":\"" + role.toString() + "\"}")); - } - - public String url() { - return baseUrl() + "/users"; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/WebhookApi.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/WebhookApi.java deleted file mode 100644 index 1454c0a48..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/api/WebhookApi.java +++ /dev/null @@ -1,56 +0,0 @@ -package de.learnlib.alex.integrationtests.resources.api; - -import java.util.List; -import java.util.stream.Collectors; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.Response; - -public class WebhookApi extends AbstractApi { - - public WebhookApi(Client client, int port) { - super(client, port); - } - - public Response create(String webhook, String jwt) { - return client.target(url()).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .post(Entity.json(webhook)); - } - - public Response get(String jwt) { - return client.target(url()).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .get(); - } - - public Response update(Integer webhookId, String webhook, String jwt) { - return client.target(url() + "/" + webhookId).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .put(Entity.json(webhook)); - } - - public Response delete(Integer webhookId, String jwt) { - return client.target(url() + "/" + webhookId).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .delete(); - } - - public Response delete(List webhookIds, String jwt) { - final List ids = webhookIds.stream().map(String::valueOf).collect(Collectors.toList()); - return client.target(url() + "/batch/" + String.join(",", ids)).request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .delete(); - } - - public Response getEvents(String jwt) { - return client.target(url() + "/events").request() - .header(HttpHeaders.AUTHORIZATION, jwt) - .get(); - } - - public String url() { - return baseUrl() + "/webhooks"; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/utils/SymbolUtils.java b/backend/src/test/java/de/learnlib/alex/integrationtests/resources/utils/SymbolUtils.java deleted file mode 100644 index 7478f200e..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/resources/utils/SymbolUtils.java +++ /dev/null @@ -1,144 +0,0 @@ -package de.learnlib.alex.integrationtests.resources.utils; - -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolActionStep; -import de.learnlib.alex.data.entities.SymbolInputParameter; -import de.learnlib.alex.data.entities.SymbolOutputMapping; -import de.learnlib.alex.data.entities.SymbolOutputParameter; -import de.learnlib.alex.data.entities.SymbolParameter; -import de.learnlib.alex.data.entities.SymbolParameterValue; -import de.learnlib.alex.data.entities.actions.misc.SetVariableAction; -import de.learnlib.alex.data.entities.actions.misc.SetVariableByJSONAttributeAction; -import de.learnlib.alex.data.entities.actions.rest.CallAction; -import de.learnlib.alex.data.entities.actions.rest.CheckStatusAction; -import de.learnlib.alex.integrationtests.resources.api.SymbolApi; -import java.util.HashMap; -import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper; - -public class SymbolUtils { - - private final ObjectMapper objectMapper = new ObjectMapper(); - - private final SymbolApi symbolApi; - - public SymbolUtils(SymbolApi symbolApi) { - this.symbolApi = symbolApi; - } - - public ParameterizedSymbol createResetSymbol(Project project, String jwt) throws Exception { - final SetVariableAction action = new SetVariableAction(); - action.setValue("test"); - action.setName("var"); - - final SymbolActionStep step = new SymbolActionStep(); - step.setAction(action); - - Symbol resetSymbol = new Symbol(); - resetSymbol.setProject(project); - resetSymbol.setName("reset"); - resetSymbol.getSteps().add(step); - - resetSymbol = symbolApi.create(project.getId().intValue(), objectMapper.writeValueAsString(resetSymbol), jwt) - .readEntity(Symbol.class); - - final ParameterizedSymbol pResetSymbol = new ParameterizedSymbol(); - pResetSymbol.setSymbol(resetSymbol); - - return pResetSymbol; - } - - public ParameterizedSymbol createAuthSymbol(Project project, String email, String password, String jwt) throws Exception { - final CallAction a1 = new CallAction(); - a1.setUrl("/rest/users/login"); - a1.setBaseUrl("Base"); - a1.setMethod(CallAction.Method.POST); - a1.setData("{\"email\":\"" + email + "\",\"password\":\"" + password + "\"}"); - - final CheckStatusAction a0 = new CheckStatusAction(); - a0.setStatus(200); - - final SymbolActionStep step0 = new SymbolActionStep(); - step0.setAction(a0); - - final SymbolActionStep step1 = new SymbolActionStep(); - step1.setAction(a1); - - final SetVariableByJSONAttributeAction a2 = new SetVariableByJSONAttributeAction(); - a2.setName("jwt"); - a2.setValue("token"); - - final SymbolActionStep step2 = new SymbolActionStep(); - step2.setAction(a2); - - final SymbolOutputParameter output = new SymbolOutputParameter(); - output.setParameterType(SymbolParameter.ParameterType.STRING); - output.setName("jwt"); - - Symbol symbol = new Symbol(); - symbol.setProject(project); - symbol.setName("auth"); - symbol.getSteps().add(step1); - symbol.getSteps().add(step0); - symbol.getSteps().add(step2); - symbol.getOutputs().add(output); - - symbol = symbolApi.create(project.getId().intValue(), objectMapper.writeValueAsString(symbol), jwt) - .readEntity(Symbol.class); - - final ParameterizedSymbol pS1 = new ParameterizedSymbol(); - pS1.setSymbol(symbol); - - final SymbolOutputMapping som = new SymbolOutputMapping(); - som.setName("jwt"); - som.setParameter(symbol.getOutputs().get(0)); - pS1.getOutputMappings().add(som); - - return pS1; - } - - public ParameterizedSymbol createGetProfileSymbol(Project project, String jwt) throws Exception { - final HashMap headers = new HashMap<>(); - headers.put("Authorization", "Bearer: {{$jwt}}"); - - final CallAction a1 = new CallAction(); - a1.setUrl("/rest/users/myself"); - a1.setBaseUrl("Base"); - a1.setMethod(CallAction.Method.GET); - a1.setHeaders(headers); - - final SymbolActionStep step1 = new SymbolActionStep(); - step1.setAction(a1); - - final CheckStatusAction a2 = new CheckStatusAction(); - a2.setStatus(200); - - final SymbolActionStep step2 = new SymbolActionStep(); - step2.setAction(a2); - - final SymbolInputParameter input = new SymbolInputParameter(); - input.setParameterType(SymbolParameter.ParameterType.STRING); - input.setName("jwt"); - - Symbol s2 = new Symbol(); - s2.setProject(project); - s2.setName("getProfile"); - s2.getSteps().add(step1); - s2.getSteps().add(step2); - s2.getInputs().add(input); - - s2 = symbolApi.create(project.getId().intValue(), objectMapper.writeValueAsString(s2), jwt) - .readEntity(Symbol.class); - - final SymbolParameterValue spv = new SymbolParameterValue(); - spv.setValue("{{$jwt}}"); - spv.setParameter(s2.getInputs().get(0)); - - final ParameterizedSymbol pS2 = new ParameterizedSymbol(); - pS2.getParameterValues().add(spv); - pS2.setSymbol(s2); - - return pS2; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/ATestPresenceServiceIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/ATestPresenceServiceIT.java deleted file mode 100644 index 5e35f6ad5..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/ATestPresenceServiceIT.java +++ /dev/null @@ -1,426 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.websocket; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.jayway.jsonpath.JsonPath; -import de.learnlib.alex.integrationtests.resources.AbstractResourceIT; -import de.learnlib.alex.integrationtests.resources.api.ProjectApi; -import de.learnlib.alex.integrationtests.resources.api.TestApi; -import de.learnlib.alex.integrationtests.websocket.util.TestPresenceServiceWSMessages; -import de.learnlib.alex.integrationtests.websocket.util.WebSocketUser; -import de.learnlib.alex.websocket.entities.WebSocketMessage; -import de.learnlib.alex.websocket.services.enums.TestPresenceServiceEnum; -import java.time.Duration; -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import javax.ws.rs.core.Response; -import org.awaitility.Awaitility; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class ATestPresenceServiceIT extends AbstractResourceIT { - - private final Duration defaultWaitTime = Duration.ofSeconds(5); - - private WebSocketUser user1; - - private WebSocketUser user2; - - private WebSocketUser user3; - - private int projectId1; - - private int projectId2; - - private int testSuiteId1; - - private int testSuiteId2; - - private int testSuiteId3; - - private int testId1; - - private int testId2; - - private int testId3; - - private int testId4; - - private TestPresenceServiceWSMessages testPresenceServiceWSMessages; - - /** - * Scenario: - * - * - Three users: user1, user2, user3. - * - two projects: project1, project2. - * - user1 is owner of project1. - * - user2 is owner of project2. - * - user2 is member of project1. - * - user3 has no project. - * - user3 is not a member of any project. - * - * @throws Exception If something goes wrong. - */ - @BeforeEach - public void pre() throws Exception { - user1 = new WebSocketUser("user1", client, port); - user2 = new WebSocketUser("user2", client, port); - user3 = new WebSocketUser("user3", client, port); - - ProjectApi projectApi = new ProjectApi(client, port); - TestApi testApi = new TestApi(client, port); - - testPresenceServiceWSMessages = new TestPresenceServiceWSMessages(); - - final Response res1 = projectApi.create("{\"name\":\"project1\",\"url\":\"http://localhost:8080/"}", user1.getJwt()); - projectId1 = JsonPath.read(res1.readEntity(String.class), "$.id"); - - projectApi.addMembers(Integer.toUnsignedLong(projectId1), Collections.singletonList(user2.getUserId()), user1.getJwt()); - - final Response res2 = projectApi.create("{\"name\":\"project2\",\"url\":\"http://localhost:8080/"}", user2.getJwt()); - projectId2 = JsonPath.read(res2.readEntity(String.class), "$.id"); - - final Response res3 = testApi.create(projectId1, "{\"name\":\"testSuite1\", \"project\": " + projectId1 + ",\"type\":\"suite\"" + "}", user1.getJwt()); - testSuiteId1 = JsonPath.read(res3.readEntity(String.class), "id"); - - final Response res4 = testApi.create(projectId1, "{\"name\":\"testSuite2\", \"project\": " + projectId1 + ", \"parent\": " + testSuiteId1 + ",\"type\":\"suite\"" + "}", user1.getJwt()); - testSuiteId2 = JsonPath.read(res4.readEntity(String.class), "id"); - - final Response res5 = testApi.create(projectId2, "{\"name\":\"testSuite3\", \"project\": " + projectId2 + ",\"type\":\"suite\"" + "}", user2.getJwt()); - testSuiteId3 = JsonPath.read(res5.readEntity(String.class), "id"); - - final Response res6 = testApi.create(projectId1, "{\"name\":\"test1\", \"project\": " + projectId1 + ", \"parent\": " + testSuiteId1 + ",\"type\":\"case\"" + "}", user1.getJwt()); - testId1 = JsonPath.read(res6.readEntity(String.class), "id"); - - final Response res7 = testApi.create(projectId1, "{\"name\":\"test2\", \"project\": " + projectId1 + ", \"parent\": " + testSuiteId1 + ",\"type\":\"case\"" + "}", user1.getJwt()); - testId2 = JsonPath.read(res7.readEntity(String.class), "id"); - - final Response res8 = testApi.create(projectId1, "{\"name\":\"test3\", \"project\": " + projectId1 + ", \"parent\": " + testSuiteId2 + ",\"type\":\"case\"" + "}", user1.getJwt()); - testId3 = JsonPath.read(res8.readEntity(String.class), "id"); - - final Response res9 = testApi.create(projectId2, "{\"name\":\"test4\", \"project\": " + projectId2 + ", \"parent\": " + testSuiteId3 + ",\"type\":\"case\"" + "}", user2.getJwt()); - testId4 = JsonPath.read(res9.readEntity(String.class), "id"); - } - - @AfterEach - @Override - public void post() throws Exception { - List.of(user1, user2, user3).forEach(u -> { - u.clearMessagesInAllSessions(); - u.forceDisconnectAll(); - }); - - super.post(); - } - - @Test - public void shouldAddTestLock() throws Exception { - user1.send("default", testPresenceServiceWSMessages.userEnteredTest(projectId1, testId1)); - final var response = user1.getNextMessage("default"); - - assertTrue(getLocks(response.getContent(), projectId1, testSuiteId1).contains("user1")); - assertEquals("user1", getUsername(response.getContent(), projectId1, testId1)); - } - - @Test - public void shouldRemoveSymbolLock() throws Exception { - user1.send("default", testPresenceServiceWSMessages.userEnteredTest(projectId1, testId1)); - final var res1 = user1.getNextMessage("default"); - assertTrue(getLocks(res1.getContent(), projectId1, testSuiteId1).contains("user1")); - assertEquals("user1", getUsername(res1.getContent(), projectId1, testId1)); - - user1.send("default", testPresenceServiceWSMessages.userLeftTest(projectId1, testId1)); - final var res2 = user1.getNextMessage("default"); - assertEquals("{}", JsonPath.read(res2.getContent(), "$.['" + projectId1 + "']").toString()); - assertEquals("{}", JsonPath.read(res2.getContent(), "$.['" + projectId1 + "']").toString()); - } - - @Test - public void shouldAddSessionToExistingSymbolLock() throws Exception { - user1.connectNewSession("otherSession"); - - user1.send("default", testPresenceServiceWSMessages.userEnteredTest(projectId1, testId1)); - WebSocketMessage response = user1.getNextMessage("default"); - - assertTrue(getLocks(response.getContent(), projectId1, testSuiteId1).contains("user1")); - assertEquals("user1", getUsername(response.getContent(), projectId1, testId1)); - - Date oldTimestamp = new Date(getTimestamp(response.getContent(), projectId1, testId1)); - - user1.send("otherSession", testPresenceServiceWSMessages.userEnteredTest(projectId1, testId1)); - response = user1.getNextMessage("default"); - - assertTrue(getLocks(response.getContent(), projectId1, testSuiteId1).contains("user1")); - assertEquals("user1", getUsername(response.getContent(), projectId1, testId1)); - - user1.send("default", testPresenceServiceWSMessages.userLeftTest(projectId1, testId1)); - response = user1.getNextMessage("default"); - - assertTrue(getLocks(response.getContent(), projectId1, testSuiteId1).contains("user1")); - assertEquals("user1", getUsername(response.getContent(), projectId1, testId1)); - - Date newTimestamp = new Date(getTimestamp(response.getContent(), projectId1, testId1)); - - assertTrue(oldTimestamp.before(newTimestamp)); - } - - @Test - public void shouldRemoveSessionFromSymbolLock() throws Exception { - user1.connectNewSession("otherSession"); - - user1.send("default", testPresenceServiceWSMessages.userEnteredTest(projectId1, testId1)); - WebSocketMessage response = user1.getNextMessage("default"); - - assertTrue(getLocks(response.getContent(), projectId1, testSuiteId1).contains("user1")); - assertEquals("user1", getUsername(response.getContent(), projectId1, testId1)); - - user1.send("otherSession", testPresenceServiceWSMessages.userEnteredTest(projectId1, testId1)); - response = user1.getNextMessage("default"); - - assertTrue(getLocks(response.getContent(), projectId1, testSuiteId1).contains("user1")); - assertEquals("user1", getUsername(response.getContent(), projectId1, testId1)); - - user1.send("default", testPresenceServiceWSMessages.userLeftTest(projectId1, testId1)); - response = user1.getNextMessage("default"); - - assertTrue(getLocks(response.getContent(), projectId1, testSuiteId1).contains("user1")); - assertEquals("user1", getUsername(response.getContent(), projectId1, testId1)); - - user1.send("otherSession", testPresenceServiceWSMessages.userLeftTest(projectId1, testId1)); - response = user1.getNextMessage("default"); - - assertEquals("{}", getProjectAsString(response.getContent(), projectId1)); - } - - @Test - public void shouldCorrectlyAssembleProjectStatus() throws Exception { - user1.connectNewSession("otherSession"); - user2.connectNewSession("otherSession"); - - user1.send("default", testPresenceServiceWSMessages.userEnteredTest(projectId1, testId1)); - user1.send("otherSession", testPresenceServiceWSMessages.userEnteredTest(projectId1, testId2)); - user2.send("default", testPresenceServiceWSMessages.userEnteredTest(projectId1, testId3)); - user2.send("otherSession", testPresenceServiceWSMessages.userEnteredTest(projectId2, testId4)); - - final var sessions = List.of("default", "otherSession"); - Awaitility.await().atMost(defaultWaitTime).until(() -> - user1.assertNumberOfMessages(sessions, List.of(3, 3)) - && user2.assertNumberOfMessages(sessions, List.of(4, 4))); - - user1.clearMessagesInAllSessions(); - user2.clearMessagesInAllSessions(); - - user2.send("default", testPresenceServiceWSMessages.requestStatus(Arrays.asList((long) projectId1, (long) projectId2))); - final var content = user2.getNextMessage("default").getContent(); - - assertTrue(getLocks(content, projectId1, testSuiteId1).contains("user1")); - assertTrue(getLocks(content, projectId1, testSuiteId1).contains("user2")); - assertTrue(getLocks(content, projectId1, testSuiteId2).contains("user2")); - assertFalse(getLocks(content, projectId1, testSuiteId2).contains("user1")); - assertTrue(getLocks(content, projectId2, testSuiteId3).contains("user2")); - assertFalse(getLocks(content, projectId2, testSuiteId3).contains("user1")); - - assertEquals("user1", getUsername(content, projectId1, testId1)); - assertEquals("user1", getUsername(content, projectId1, testId2)); - assertEquals("user2", getUsername(content, projectId1, testId3)); - assertEquals("user2", getUsername(content, projectId2, testId4)); - } - - @Test - public void shouldSupportMultipleUserSessions() throws Exception { - user1.connectNewSession("otherSession"); - user2.connectNewSession("otherSession"); - - user1.send("default", testPresenceServiceWSMessages.userEnteredTest(projectId1, testId1)); - user1.send("otherSession", testPresenceServiceWSMessages.userEnteredTest(projectId1, testId2)); - user2.send("default", testPresenceServiceWSMessages.userEnteredTest(projectId1, testId3)); - user2.send("otherSession", testPresenceServiceWSMessages.userEnteredTest(projectId2, testId4)); - - final var sessions = List.of("default", "otherSession"); - Awaitility.await().atMost(defaultWaitTime).until(() -> - user1.assertNumberOfMessages(sessions, List.of(3, 3)) - && user2.assertNumberOfMessages(sessions, List.of(4, 4))); - - user1.send("default", testPresenceServiceWSMessages.userLeftTest(projectId1, testId1)); - user1.send("otherSession", testPresenceServiceWSMessages.userLeftTest(projectId1, testId2)); - user2.send("default", testPresenceServiceWSMessages.userLeftTest(projectId1, testId3)); - user2.send("otherSession", testPresenceServiceWSMessages.userLeftTest(projectId2, testId4)); - - Awaitility.await().atMost(defaultWaitTime).until(() -> - user1.assertNumberOfMessages(sessions, List.of(6, 6)) - && user2.assertNumberOfMessages(sessions, List.of(8, 8))); - - user1.clearMessagesInAllSessions(); - user2.clearMessagesInAllSessions(); - user2.send("default", testPresenceServiceWSMessages.requestStatus(Arrays.asList((long) projectId1, (long) projectId2))); - final var response = user2.getNextMessage("default"); - - assertEquals("{}", getProjectAsString(response.getContent(), projectId1)); - assertEquals("{}", getProjectAsString(response.getContent(), projectId2)); - } - - @Test - public void shouldProcessSessionDisconnect() throws Exception { - user2.send("default", testPresenceServiceWSMessages.userEnteredTest(projectId1, testId1)); - - final var res1 = user1.getNextMessage("default"); - assertTrue(getLocks(res1.getContent(), projectId1, testSuiteId1).contains("user2")); - assertEquals("user2", getUsername(res1.getContent(), projectId1, testId1)); - - user2.forceDisconnect("default"); - final var res2 = user1.getNextMessage("default"); - assertEquals("{}", getProjectAsString(res2.getContent(), projectId1)); - } - - @Test - public void shouldIgnoreDuplicateEnteredMessage() throws Exception { - final var res1 = user1.sendAndReceive("default", testPresenceServiceWSMessages.userEnteredTest(projectId1, testId1)); - assertTrue(getLocks(res1.getContent(), projectId1, testSuiteId1).contains("user1")); - assertEquals("user1", getUsername(res1.getContent(), projectId1, testId1)); - - final var res2 = user1.sendAndReceive("default", testPresenceServiceWSMessages.userEnteredTest(projectId1, testId1)); - assertNull(res2); - } - - @Test - public void shouldIgnoreDuplicateLeftMessage() throws Exception { - final var res1 = user1.sendAndReceive("default", testPresenceServiceWSMessages.userEnteredTest(projectId1, testId1)); - assertTrue(getLocks(res1.getContent(), projectId1, testSuiteId1).contains("user1")); - assertEquals("user1", getUsername(res1.getContent(), projectId1, testId1)); - - final var res2 = user1.sendAndReceive("default", testPresenceServiceWSMessages.userLeftTest(projectId1, testId1)); - assertEquals("{}", getProjectAsString(res2.getContent(), projectId1)); - - final var res3 = user1.sendAndReceive("default", testPresenceServiceWSMessages.userLeftTest(projectId1, testId1)); - assertNull(res3); - } - - @Test - public void shouldSwitchSymbolLock() throws Exception { - user1.send("default", testPresenceServiceWSMessages.userEnteredTest(projectId1, testId1)); - - final var res1 = user1.getNextMessage("default"); - assertTrue(getLocks(res1.getContent(), projectId1, testSuiteId1).contains("user1")); - assertEquals("user1", getUsername(res1.getContent(), projectId1, testId1)); - - user1.send("default", testPresenceServiceWSMessages.userEnteredTest(projectId1, testId2)); - final var res2 = user1.getNextMessage("default"); - assertEquals("{}", getProjectAsString(res2.getContent(), projectId1)); - assertEquals("{}", getProjectAsString(res2.getContent(), projectId1)); - - final var res3 = user1.getNextMessage("default"); - assertTrue(getLocks(res3.getContent(), projectId1, testSuiteId1).contains("user1")); - assertEquals("user1", getUsername(res3.getContent(), projectId1, testId2)); - } - - @Test - public void shouldBroadcastUpdatesCorrectly() throws Exception { - user2.connectNewSession("otherSession"); - - user1.send("default", testPresenceServiceWSMessages.userEnteredTest(projectId1, testId1)); - - final var res1 = user1.getNextMessage("default"); - assertTrue(getLocks(res1.getContent(), projectId1, testSuiteId1).contains("user1")); - assertEquals("user1", getUsername(res1.getContent(), projectId1, testId1)); - - final var res2 = user2.getNextMessage("default"); - assertTrue(getLocks(res2.getContent(), projectId1, testSuiteId1).contains("user1")); - assertEquals("user1", getUsername(res2.getContent(), projectId1, testId1)); - - final var res3 = user2.getNextMessage("otherSession"); - assertTrue(getLocks(res3.getContent(), projectId1, testSuiteId1).contains("user1")); - assertEquals("user1", getUsername(res3.getContent(), projectId1, testId1)); - - final var res4 = user3.getNextMessage("default"); - assertNull(res4); - } - - @Test - public void shouldNotSendProjectStatusToUnauthorizedUser() throws Exception { - final var message = testPresenceServiceWSMessages.requestStatus(Collections.singletonList((long) projectId1)); - final var response = user3.sendAndReceive("default", message); - assertEquals("You are not allowed to access the project.", getDescription(response.getContent())); - } - - @Test - public void shouldRejectMalformedContentInStatusRequestMessage() throws Exception { - final var badMessage = new WebSocketMessage(); - badMessage.setEntity(TestPresenceServiceEnum.TEST_PRESENCE_SERVICE.name()); - badMessage.setType(TestPresenceServiceEnum.STATUS_REQUEST.name()); - badMessage.setContent("malformed content"); - - final var response = user1.sendAndReceive("default", badMessage); - assertEquals("Received malformed content.", getDescription(response.getContent())); - } - - @Test - public void shouldRejectMalformedContentInUserEnteredMessage() throws Exception { - final var badMessage = new WebSocketMessage(); - badMessage.setEntity(TestPresenceServiceEnum.TEST_PRESENCE_SERVICE.name()); - badMessage.setType(TestPresenceServiceEnum.USER_ENTERED.name()); - badMessage.setContent("malformed content"); - - final var response = user1.sendAndReceive("default", badMessage); - assertEquals("Received malformed content.", getDescription(response.getContent())); - } - - @Test - public void shouldRejectMalformedContentInUserLeftMessage() throws Exception { - final var badMessage = new WebSocketMessage(); - badMessage.setEntity(TestPresenceServiceEnum.TEST_PRESENCE_SERVICE.name()); - badMessage.setType(TestPresenceServiceEnum.USER_LEFT.name()); - badMessage.setContent("malformed content"); - - final var response = user1.sendAndReceive("default", badMessage); - assertEquals("Received malformed content.", getDescription(response.getContent())); - } - - @Test - public void shouldRejectStatusRequestWithNonExistentProject() throws Exception { - final var message = testPresenceServiceWSMessages.requestStatus(Collections.singletonList(-1L)); - final var response = user1.sendAndReceive("default", message); - assertEquals("Project with id -1 not found.", getDescription(response.getContent())); - } - - private List getLocks(String content, int projectId, int testId) { - return JsonPath.read(content, "$.['" + projectId + "'].['" + testId + "'].locks"); - } - - private String getUsername(String content, int projectId, int testId) { - return JsonPath.read(content, "$.['" + projectId + "'].['" + testId + "'].username"); - } - - private Long getTimestamp(String content, int projectId, int testId) { - return JsonPath.read(content, "$.['" + projectId + "'].['" + testId + "'].timestamp"); - } - - private String getProjectAsString(String content, int projectId) { - return JsonPath.read(content, "$.['" + projectId + "']").toString(); - } - - private String getDescription(String content) { - return JsonPath.read(content, "$.description"); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/ProjectPresenceServiceIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/ProjectPresenceServiceIT.java deleted file mode 100644 index e6f579e64..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/ProjectPresenceServiceIT.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.websocket; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNull; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.jayway.jsonpath.JsonPath; -import de.learnlib.alex.integrationtests.resources.AbstractResourceIT; -import de.learnlib.alex.integrationtests.resources.api.ProjectApi; -import de.learnlib.alex.integrationtests.websocket.util.ProjectPresenceServiceWSMessages; -import de.learnlib.alex.integrationtests.websocket.util.WebSocketUser; -import de.learnlib.alex.websocket.entities.WebSocketMessage; -import de.learnlib.alex.websocket.services.enums.ProjectPresenceServiceEnum; -import java.time.Duration; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import javax.ws.rs.core.Response; -import org.awaitility.Awaitility; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class ProjectPresenceServiceIT extends AbstractResourceIT { - - private WebSocketUser user1; - - private WebSocketUser user2; - - private WebSocketUser user3; - - private long projectId1; - - private long projectId2; - - private ProjectApi projectApi; - - private ProjectPresenceServiceWSMessages projectPresenceServiceWSMessages; - - /** - * Scenario: - * - * - Three users: user1, user2, user3. - * - two projects: project1, project2. - * - user1 is owner of project1. - * - user2 is owner of project2. - * - user2 is member of project1. - * - user3 has no project. - * - user3 is not a member of any project. - * - * @throws Exception If something goes wrong. - */ - @BeforeEach - public void pre() throws Exception { - user1 = new WebSocketUser("user1", client, port); - user2 = new WebSocketUser("user2", client, port); - user3 = new WebSocketUser("user3", client, port); - - projectApi = new ProjectApi(client, port); - projectPresenceServiceWSMessages = new ProjectPresenceServiceWSMessages(); - - final Response res1 = projectApi.create("{\"name\":\"project1\",\"url\":\"http://localhost:8080/"}", user1.getJwt()); - projectId1 = Integer.toUnsignedLong(JsonPath.read(res1.readEntity(String.class), "$.id")); - projectApi.addMembers(projectId1, Collections.singletonList(user2.getUserId()), user1.getJwt()); - - final Response res2 = projectApi.create("{\"name\":\"project2\",\"url\":\"http://localhost:8080/"}", user2.getJwt()); - projectId2 = Integer.toUnsignedLong(JsonPath.read(res2.readEntity(String.class), "$.id")); - } - - @AfterEach - @Override - public void post() throws Exception { - List.of(user1, user2, user3).forEach(u -> { - u.clearMessagesInAllSessions(); - u.forceDisconnectAll(); - }); - - super.post(); - } - - @Test - public void shouldAddUserPresence() throws JsonProcessingException, InterruptedException { - user1.send("default", projectPresenceServiceWSMessages.userEnteredProject(projectId1)); - final var response = user1.getNextMessage("default"); - JsonPath.read(response.getContent(), "$.['" + projectId1 + "'].userColors.user1"); - } - - @Test - public void shouldRemoveUserPresence() throws JsonProcessingException, InterruptedException { - user1.send("default", projectPresenceServiceWSMessages.userEnteredProject(projectId1)); - final var res1 = user1.getNextMessage("default"); - JsonPath.read(res1.getContent(), "$.['" + projectId1 + "'].userColors.user1"); - - user1.send("default", projectPresenceServiceWSMessages.userLeftProject(projectId1)); - final var res2 = user1.getNextMessage("default"); - assertEquals("{}", JsonPath.read(res2.getContent(), "$.['" + projectId1 + "']").toString()); - } - - @Test - public void shouldSupportMultipleUserSessions() throws Exception { - user1.connectNewSession("otherSession"); - - user1.send("default", projectPresenceServiceWSMessages.userEnteredProject(projectId1)); - final var res1 = user1.getNextMessage("default"); - final var color = JsonPath.read(res1.getContent(), "$.['" + projectId1 + "'].userColors.user1"); - - user1.send("otherSession", projectPresenceServiceWSMessages.userEnteredProject(projectId1)); - final var res2 = user1.getNextMessage("default"); - assertEquals(color, JsonPath.read(res2.getContent(), "$.['" + projectId1 + "'].userColors.user1")); - - user1.send("default", projectPresenceServiceWSMessages.userLeftProject(projectId1)); - final var res3 = user1.getNextMessage("default"); - assertEquals(color, JsonPath.read(res3.getContent(), "$.['" + projectId1 + "'].userColors.user1")); - - user1.send("otherSession", projectPresenceServiceWSMessages.userLeftProject(projectId1)); - final var res4 = user1.getNextMessage("default"); - assertEquals("{}", JsonPath.read(res4.getContent(), "$.['" + projectId1 + "']").toString()); - } - - @Test - public void shouldReuseMaximumContrastColorsFirst() throws JsonProcessingException, InterruptedException { - projectApi.addMembers(projectId1, Collections.singletonList(user3.getUserId()), user1.getJwt()); - - user1.send("default", projectPresenceServiceWSMessages.userEnteredProject(projectId1)); - final var res1 = user1.getNextMessage("default"); - final var color1 = JsonPath.read(res1.getContent(), "$.['" + projectId1 + "'].userColors.user1"); - - user2.send("default", projectPresenceServiceWSMessages.userEnteredProject(projectId1)); - final var res2 = user1.getNextMessage("default"); - final var color2 = JsonPath.read(res2.getContent(), "$.['" + projectId1 + "'].userColors.user2"); - assertNotEquals(color2, color1); - - user1.send("default", projectPresenceServiceWSMessages.userLeftProject(projectId1)); - user1.getNextMessage("default"); - - user3.send("default", projectPresenceServiceWSMessages.userEnteredProject(projectId1)); - final var res3 = user1.getNextMessage("default"); - assertEquals(color1, JsonPath.read(res3.getContent(), "$.['" + projectId1 + "'].userColors.user3")); - } - - @Test - public void shouldSwitchUserPresence() throws JsonProcessingException, InterruptedException { - user2.send("default", projectPresenceServiceWSMessages.userEnteredProject(projectId1)); - final var res1 = user2.getNextMessage("default"); - JsonPath.read(res1.getContent(), "$.['" + projectId1 + "'].userColors.user2"); - - user2.send("default", projectPresenceServiceWSMessages.userEnteredProject((projectId2))); - final var res2 = user2.getNextMessage("default"); - assertEquals("{}", JsonPath.read(res2.getContent(), "$.['" + projectId1 + "']").toString()); - - final var res3 = user2.getNextMessage("default"); - JsonPath.read(res3.getContent(), "$.['" + projectId2 + "'].userColors.user2"); - } - - @Test - public void shouldIgnoreDuplicateEnteredMessage() throws InterruptedException, JsonProcessingException { - user1.send("default", projectPresenceServiceWSMessages.userEnteredProject(projectId1)); - final var res1 = user1.getNextMessage("default"); - JsonPath.read(res1.getContent(), "$.['" + projectId1 + "'].userColors.user1"); - - user1.send("default", projectPresenceServiceWSMessages.userEnteredProject(projectId1)); - final var res2 = user1.getNextMessage("default"); - assertNull(res2); - } - - @Test - public void shouldIgnoreDuplicateLeftMessage() throws InterruptedException, JsonProcessingException { - user1.send("default", projectPresenceServiceWSMessages.userEnteredProject(projectId1)); - final var res1 = user1.getNextMessage("default"); - JsonPath.read(res1.getContent(), "$.['" + projectId1 + "'].userColors.user1"); - - user1.send("default", projectPresenceServiceWSMessages.userLeftProject(projectId1)); - final var res2 = user1.getNextMessage("default"); - assertEquals("{}", JsonPath.read(res2.getContent(), "$.['" + projectId1 + "']").toString()); - - user1.send("default", projectPresenceServiceWSMessages.userLeftProject(projectId1)); - final var res3 = user1.getNextMessage("default"); - assertNull(res3); - } - - @Test - public void shouldCorrectlyAssembleProjectStatus() throws Exception { - user1.connectNewSession("otherSession"); - user2.connectNewSession("otherSession"); - - user1.send("default", projectPresenceServiceWSMessages.userEnteredProject(projectId1)); - user2.send("default", projectPresenceServiceWSMessages.userEnteredProject(projectId1)); - user2.send("otherSession", projectPresenceServiceWSMessages.userEnteredProject(projectId2)); - - final var sessions = List.of("default", "otherSession"); - Awaitility.await().atMost(Duration.ofSeconds(5)).until(() -> - user1.assertNumberOfMessages(sessions, List.of(2, 2)) - && user2.assertNumberOfMessages(sessions, List.of(3, 3))); - - user1.clearMessagesInAllSessions(); - user2.clearMessagesInAllSessions(); - - user2.send("default", projectPresenceServiceWSMessages.requestStatus(Arrays.asList(projectId1, projectId2))); - final var response = user2.getNextMessage("default"); - - JsonPath.read(response.getContent(), "$.['" + projectId1 + "'].userColors.user1"); - JsonPath.read(response.getContent(), "$.['" + projectId1 + "'].userColors.user2"); - JsonPath.read(response.getContent(), "$.['" + projectId2 + "'].userColors.user2"); - } - - @Test - public void shouldProcessSessionDisconnect() throws Exception { - user2.send("default", projectPresenceServiceWSMessages.userEnteredProject(projectId1)); - final var res1 = user1.getNextMessage("default"); - JsonPath.read(res1.getContent(), "$.['" + projectId1 + "'].userColors.user2"); - - user2.forceDisconnect("default"); - final var res2 = user1.getNextMessage("default"); - assertEquals("{}", JsonPath.read(res2.getContent(), "$.['" + projectId1 + "']").toString()); - } - - @Test - public void shouldBroadcastUpdatesCorrectly() throws Exception { - user2.connectNewSession("otherSession"); - - user1.send("default", projectPresenceServiceWSMessages.userEnteredProject(projectId1)); - - final var res1 = user1.getNextMessage("default"); - JsonPath.read(res1.getContent(), "$.['" + projectId1 + "'].userColors.user1"); - - final var res2 = user2.getNextMessage("default"); - JsonPath.read(res2.getContent(), "$.['" + projectId1 + "'].userColors.user1"); - - final var res3 = user2.getNextMessage("otherSession"); - JsonPath.read(res3.getContent(), "$.['" + projectId1 + "'].userColors.user1"); - - final var res4 = user3.getNextMessage("default"); - assertNull(res4); - } - - @Test - public void shouldNotSendProjectStatusToUnauthorizedUser() throws Exception { - user3.send("default", projectPresenceServiceWSMessages.requestStatus(Collections.singletonList(projectId1))); - - final var response = user3.getNextMessage("default"); - assertEquals("You are not allowed to access the project.", getDescription(response.getContent())); - } - - @Test - public void shouldRejectMalformedContentInStatusRequestMessage() throws Exception { - final var badMessage = new WebSocketMessage(); - badMessage.setEntity(ProjectPresenceServiceEnum.PROJECT_PRESENCE_SERVICE.name()); - badMessage.setType(ProjectPresenceServiceEnum.STATUS_REQUEST.name()); - badMessage.setContent("malformed content"); - user1.send("default", badMessage); - - final var response = user1.getNextMessage("default"); - assertEquals("Received malformed content.", getDescription(response.getContent())); - } - - @Test - public void shouldRejectMalformedContentInUserEnteredMessage() throws Exception { - final var badMessage = new WebSocketMessage(); - badMessage.setEntity(ProjectPresenceServiceEnum.PROJECT_PRESENCE_SERVICE.name()); - badMessage.setType(ProjectPresenceServiceEnum.USER_ENTERED.name()); - badMessage.setContent("malformed content"); - user1.send("default", badMessage); - - final var response = user1.getNextMessage("default"); - assertEquals("Received malformed content.", getDescription(response.getContent())); - } - - @Test - public void shouldRejectMalformedContentInUserLeftMessage() throws Exception { - final var badMessage = new WebSocketMessage(); - badMessage.setEntity(ProjectPresenceServiceEnum.PROJECT_PRESENCE_SERVICE.name()); - badMessage.setType(ProjectPresenceServiceEnum.USER_LEFT.name()); - badMessage.setContent("malformed content"); - user1.send("default", badMessage); - - final var response = user1.getNextMessage("default"); - assertEquals("Received malformed content.", getDescription(response.getContent())); - } - - @Test - public void shouldRejectStatusRequestWithNonExistentProject() throws Exception { - user1.send("default", projectPresenceServiceWSMessages.requestStatus(Collections.singletonList(-1L))); - - final var response = user1.getNextMessage("default"); - assertEquals("Project with id -1 not found.", getDescription(response.getContent())); - } - - private String getDescription(String content) { - return JsonPath.read(content, "$.description"); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/SymbolPresenceServiceIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/SymbolPresenceServiceIT.java deleted file mode 100644 index c75ce6507..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/SymbolPresenceServiceIT.java +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.websocket; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.jayway.jsonpath.JsonPath; -import de.learnlib.alex.integrationtests.resources.AbstractResourceIT; -import de.learnlib.alex.integrationtests.resources.api.ProjectApi; -import de.learnlib.alex.integrationtests.resources.api.SymbolApi; -import de.learnlib.alex.integrationtests.resources.api.SymbolGroupApi; -import de.learnlib.alex.integrationtests.websocket.util.SymbolPresenceServiceWSMessages; -import de.learnlib.alex.integrationtests.websocket.util.WebSocketUser; -import de.learnlib.alex.websocket.entities.WebSocketMessage; -import de.learnlib.alex.websocket.services.enums.SymbolPresenceServiceEnum; -import java.time.Duration; -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import javax.ws.rs.core.Response; -import org.awaitility.Awaitility; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class SymbolPresenceServiceIT extends AbstractResourceIT { - - private final Duration defaultWaitTime = Duration.ofSeconds(5); - - private WebSocketUser user1; - - private WebSocketUser user2; - - private WebSocketUser user3; - - private int projectId1; - - private int projectId2; - - private int symbolGroupId1; - - private int symbolGroupId2; - - private int symbolGroupId3; - - private int symbolId1; - - private int symbolId2; - - private int symbolId3; - - private int symbolId4; - - private SymbolPresenceServiceWSMessages symbolPresenceServiceWSMessages; - - /** - * Scenario: - * - * - Three users: user1, user2, user3. - * - two projects: project1, project2. - * - user1 is owner of project1. - * - user2 is owner of project2. - * - user2 is member of project1. - * - user3 has no project. - * - user3 is not a member of any project. - * - * @throws Exception If something goes wrong. - */ - @BeforeEach - public void pre() throws Exception { - user1 = new WebSocketUser("user1", client, port); - user2 = new WebSocketUser("user2", client, port); - user3 = new WebSocketUser("user3", client, port); - - final var projectApi = new ProjectApi(client, port); - final var symbolGroupApi = new SymbolGroupApi(client, port); - final var symbolApi = new SymbolApi(client, port); - - symbolPresenceServiceWSMessages = new SymbolPresenceServiceWSMessages(); - - final Response res1 = projectApi.create("{\"name\":\"project1\",\"url\":\"http://localhost:8080/"}", user1.getJwt()); - projectId1 = JsonPath.read(res1.readEntity(String.class), "$.id"); - - projectApi.addMembers(Integer.toUnsignedLong(projectId1), Collections.singletonList(user2.getUserId()), user1.getJwt()); - - final Response res2 = projectApi.create("{\"name\":\"project2\",\"url\":\"http://localhost:8080/"}", user2.getJwt()); - projectId2 = JsonPath.read(res2.readEntity(String.class), "$.id"); - - final Response res3 = symbolGroupApi.create(projectId1, "{\"name\":\"group1\", \"project\": " + projectId1 + "}", user1.getJwt()); - symbolGroupId1 = JsonPath.read(res3.readEntity(String.class), "id"); - - final Response res4 = symbolGroupApi.create(projectId1, "{\"name\":\"group2\", \"project\": " + projectId1 + ", \"parent\": " + symbolGroupId1 + "}", user1.getJwt()); - symbolGroupId2 = JsonPath.read(res4.readEntity(String.class), "id"); - - final Response res5 = symbolGroupApi.create(projectId2, "{\"name\":\"group3\", \"project\": " + projectId2 + "}", user2.getJwt()); - symbolGroupId3 = JsonPath.read(res5.readEntity(String.class), "id"); - - final Response res6 = symbolApi.create(projectId1, "{\"name\":\"symbol1\", \"project\": " + projectId1 + ", \"group\": " + symbolGroupId1 + "}", user1.getJwt()); - symbolId1 = JsonPath.read(res6.readEntity(String.class), "id"); - - final Response res7 = symbolApi.create(projectId1, "{\"name\":\"symbol2\", \"project\": " + projectId1 + ", \"group\": " + symbolGroupId1 + "}", user1.getJwt()); - symbolId2 = JsonPath.read(res7.readEntity(String.class), "id"); - - final Response res8 = symbolApi.create(projectId1, "{\"name\":\"symbol3\", \"project\": " + projectId1 + ", \"group\": " + symbolGroupId2 + "}", user1.getJwt()); - symbolId3 = JsonPath.read(res8.readEntity(String.class), "id"); - - final Response res9 = symbolApi.create(projectId2, "{\"name\":\"symbol4\", \"project\": " + projectId2 + ", \"group\": " + symbolGroupId3 + "}", user2.getJwt()); - symbolId4 = JsonPath.read(res9.readEntity(String.class), "id"); - } - - @AfterEach - @Override - public void post() throws Exception { - List.of(user1, user2, user3).forEach(u -> { - u.clearMessagesInAllSessions(); - u.forceDisconnectAll(); - }); - - super.post(); - } - - @Test - public void shouldAddSymbolLock() throws Exception { - user1.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, symbolId1)); - final WebSocketMessage response = user1.getNextMessage("default"); - - final var content = response.getContent(); - assertTrue(getLocks(content, projectId1, symbolGroupId1).contains("user1")); - assertEquals("user1", getUsername(content, projectId1, symbolId1)); - } - - @Test - public void shouldRemoveSymbolLock() throws Exception { - user1.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, symbolId1)); - WebSocketMessage response = user1.getNextMessage("default"); - - assertTrue(getLocks(response.getContent(), projectId1, symbolGroupId1).contains("user1")); - assertEquals("user1", getUsername(response.getContent(), projectId1, symbolId1)); - - user1.send("default", symbolPresenceServiceWSMessages.userLeftSymbol(projectId1, symbolId1)); - response = user1.getNextMessage("default"); - - assertEquals("{}", getSymbolsAsString(response.getContent(), projectId1)); - assertEquals("{}", getGroupsAsString(response.getContent(), projectId1)); - } - - @Test - public void shouldAddSessionToExistingSymbolLock() throws Exception { - user1.connectNewSession("otherSession"); - - user1.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, symbolId1)); - WebSocketMessage response = user1.getNextMessage("default"); - - assertTrue(getLocks(response.getContent(), projectId1, symbolGroupId1).contains("user1")); - assertEquals("user1", getUsername(response.getContent(), projectId1, symbolId1)); - - Date oldTimestamp = new Date(getTimestamp(response.getContent(), projectId1, symbolId1)); - - user1.send("otherSession", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, symbolId1)); - response = user1.getNextMessage("default"); - - assertTrue(getLocks(response.getContent(), projectId1, symbolGroupId1).contains("user1")); - assertEquals("user1", getUsername(response.getContent(), projectId1, symbolId1)); - - user1.send("default", symbolPresenceServiceWSMessages.userLeftSymbol(projectId1, symbolId1)); - response = user1.getNextMessage("default"); - - assertTrue(getLocks(response.getContent(), projectId1, symbolGroupId1).contains("user1")); - assertEquals("user1", getUsername(response.getContent(), projectId1, symbolId1)); - - Date newTimestamp = new Date(getTimestamp(response.getContent(), projectId1, symbolId1)); - - assertTrue(oldTimestamp.before(newTimestamp)); - } - - @Test - public void shouldRemoveSessionFromSymbolLock() throws Exception { - user1.connectNewSession("otherSession"); - - user1.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, symbolId1)); - WebSocketMessage response = user1.getNextMessage("default"); - - assertTrue(getLocks(response.getContent(), projectId1, symbolGroupId1).contains("user1")); - assertEquals("user1", getUsername(response.getContent(), projectId1, symbolId1)); - - user1.send("otherSession", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, symbolId1)); - response = user1.getNextMessage("default"); - - assertTrue(getLocks(response.getContent(), projectId1, symbolGroupId1).contains("user1")); - assertEquals("user1", getUsername(response.getContent(), projectId1, symbolId1)); - - user1.send("default", symbolPresenceServiceWSMessages.userLeftSymbol(projectId1, symbolId1)); - response = user1.getNextMessage("default"); - - assertTrue(getLocks(response.getContent(), projectId1, symbolGroupId1).contains("user1")); - assertEquals("user1", getUsername(response.getContent(), projectId1, symbolId1)); - - user1.send("otherSession", symbolPresenceServiceWSMessages.userLeftSymbol(projectId1, symbolId1)); - response = user1.getNextMessage("default"); - - assertEquals("{}", getSymbolsAsString(response.getContent(), projectId1)); - assertEquals("{}", getGroupsAsString(response.getContent(), projectId1)); - } - - @Test - public void shouldCorrectlyAssembleProjectStatus() throws Exception { - user1.connectNewSession("otherSession"); - user2.connectNewSession("otherSession"); - - user1.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, symbolId1)); - user1.send("otherSession", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, symbolId2)); - user2.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, symbolId3)); - user2.send("otherSession", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId2, symbolId4)); - - final var sessions = List.of("default", "otherSession"); - Awaitility.await().atMost(defaultWaitTime).until(() -> - user1.assertNumberOfMessages(sessions, List.of(3, 3)) - && user2.assertNumberOfMessages(sessions, List.of(4, 4))); - - user1.clearMessagesInAllSessions(); - user2.clearMessagesInAllSessions(); - - user2.send("default", symbolPresenceServiceWSMessages.requestStatus(Arrays.asList((long) projectId1, (long) projectId2))); - final var content = user2.getNextMessage("default").getContent(); - - assertTrue(getLocks(content, projectId1, symbolGroupId1).contains("user1")); - assertTrue(getLocks(content, projectId1, symbolGroupId1).contains("user2")); - assertTrue(getLocks(content, projectId1, symbolGroupId2).contains("user2")); - assertFalse(getLocks(content, projectId1, symbolGroupId2).contains("user1")); - assertTrue(getLocks(content, projectId2, symbolGroupId3).contains("user2")); - assertFalse(getLocks(content, projectId2, symbolGroupId3).contains("user1")); - - assertEquals("user1", getUsername(content, projectId1, symbolId1)); - assertEquals("user1", getUsername(content, projectId1, symbolId2)); - assertEquals("user2", getUsername(content, projectId1, symbolId3)); - assertEquals("user2", getUsername(content, projectId2, symbolId4)); - } - - @Test - public void shouldSupportMultipleUserSessions() throws Exception { - user1.connectNewSession("otherSession"); - user2.connectNewSession("otherSession"); - - user1.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, symbolId1)); - user1.send("otherSession", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, symbolId2)); - user2.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, symbolId3)); - user2.send("otherSession", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId2, symbolId4)); - - final var sessions = List.of("default", "otherSession"); - Awaitility.await().atMost(defaultWaitTime).until(() -> - user1.assertNumberOfMessages(sessions, List.of(3, 3)) - && user2.assertNumberOfMessages(sessions, List.of(4, 4))); - - user1.send("default", symbolPresenceServiceWSMessages.userLeftSymbol(projectId1, symbolId1)); - user1.send("otherSession", symbolPresenceServiceWSMessages.userLeftSymbol(projectId1, symbolId2)); - user2.send("default", symbolPresenceServiceWSMessages.userLeftSymbol(projectId1, symbolId3)); - user2.send("otherSession", symbolPresenceServiceWSMessages.userLeftSymbol(projectId2, symbolId4)); - - Awaitility.await().atMost(defaultWaitTime).until(() -> - user1.assertNumberOfMessages(sessions, List.of(6, 6)) - && user2.assertNumberOfMessages(sessions, List.of(8, 8))); - - user1.clearMessagesInAllSessions(); - user2.clearMessagesInAllSessions(); - - user2.send("default", symbolPresenceServiceWSMessages.requestStatus(Arrays.asList((long) projectId1, (long) projectId2))); - final WebSocketMessage response = user2.getNextMessage("default"); - - assertEquals("{}", getGroupsAsString(response.getContent(), projectId1)); - assertEquals("{}", getSymbolsAsString(response.getContent(), projectId1)); - assertEquals("{}", JsonPath.read(response.getContent(), "$.['" + projectId2 + "'].groups").toString()); - assertEquals("{}", JsonPath.read(response.getContent(), "$.['" + projectId2 + "'].symbols").toString()); - } - - @Test - public void shouldProcessSessionDisconnect() throws Exception { - user2.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, symbolId1)); - - WebSocketMessage response = user1.getNextMessage("default"); - assertTrue(getLocks(response.getContent(), projectId1, symbolGroupId1).contains("user2")); - assertEquals("user2", getUsername(response.getContent(), projectId1, symbolId1)); - - user2.forceDisconnect("default"); - response = user1.getNextMessage("default"); - assertEquals("{}", getSymbolsAsString(response.getContent(), projectId1)); - assertEquals("{}", getGroupsAsString(response.getContent(), projectId1)); - } - - @Test - public void shouldIgnoreDuplicateEnteredMessage() throws Exception { - user1.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, symbolId1)); - - WebSocketMessage response = user1.getNextMessage("default"); - assertTrue(getLocks(response.getContent(), projectId1, symbolGroupId1).contains("user1")); - assertEquals("user1", getUsername(response.getContent(), projectId1, symbolId1)); - - user1.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, symbolId1)); - response = user1.getNextMessage("default"); - assertNull(response); - } - - @Test - public void shouldIgnoreDuplicateLeftMessage() throws Exception { - user1.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, symbolId1)); - - WebSocketMessage response = user1.getNextMessage("default"); - assertTrue(getLocks(response.getContent(), projectId1, symbolGroupId1).contains("user1")); - assertEquals("user1", getUsername(response.getContent(), projectId1, symbolId1)); - - user1.send("default", symbolPresenceServiceWSMessages.userLeftSymbol(projectId1, symbolId1)); - response = user1.getNextMessage("default"); - assertEquals("{}", getSymbolsAsString(response.getContent(), projectId1)); - assertEquals("{}", getGroupsAsString(response.getContent(), projectId1)); - - user1.send("default", symbolPresenceServiceWSMessages.userLeftSymbol(projectId1, symbolId1)); - response = user1.getNextMessage("default"); - assertNull(response); - } - - @Test - public void shouldSwitchSymbolLock() throws Exception { - user1.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, symbolId1)); - - WebSocketMessage response = user1.getNextMessage("default"); - assertTrue(getLocks(response.getContent(), projectId1, symbolGroupId1).contains("user1")); - assertEquals("user1", getUsername(response.getContent(), projectId1, symbolId1)); - - user1.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, symbolId2)); - response = user1.getNextMessage("default"); - assertEquals("{}", getSymbolsAsString(response.getContent(), projectId1)); - assertEquals("{}", getGroupsAsString(response.getContent(), projectId1)); - - response = user1.getNextMessage("default"); - assertTrue(getLocks(response.getContent(), projectId1, symbolGroupId1).contains("user1")); - assertEquals("user1", getUsername(response.getContent(), projectId1, symbolId2)); - } - - @Test - public void shouldBroadcastUpdatesCorrectly() throws Exception { - user2.connectNewSession("otherSession"); - - user1.send("default", symbolPresenceServiceWSMessages.userEnteredSymbol(projectId1, symbolId1)); - - final var res1 = user1.getNextMessage("default"); - assertTrue(getLocks(res1.getContent(), projectId1, symbolGroupId1).contains("user1")); - assertEquals("user1", getUsername(res1.getContent(), projectId1, symbolId1)); - - final var res2 = user2.getNextMessage("default"); - assertTrue(getLocks(res2.getContent(), projectId1, symbolGroupId1).contains("user1")); - assertEquals("user1", getUsername(res2.getContent(), projectId1, symbolId1)); - - final var res3 = user2.getNextMessage("otherSession"); - assertTrue(getLocks(res3.getContent(), projectId1, symbolGroupId1).contains("user1")); - assertEquals("user1", getUsername(res3.getContent(), projectId1, symbolId1)); - - final var res4 = user3.getNextMessage("default"); - assertNull(res4); - } - - @Test - public void shouldNotSendProjectStatusToUnauthorizedUser() throws Exception { - user3.send("default", symbolPresenceServiceWSMessages.requestStatus(Collections.singletonList((long) projectId1))); - - final var response = user3.getNextMessage("default"); - assertEquals("You are not allowed to access the project.", JsonPath.read(response.getContent(), "$.description")); - } - - @Test - public void shouldRejectMalformedContentInStatusRequestMessage() throws Exception { - final WebSocketMessage badMessage = new WebSocketMessage(); - badMessage.setEntity(SymbolPresenceServiceEnum.SYMBOL_PRESENCE_SERVICE.name()); - badMessage.setType(SymbolPresenceServiceEnum.STATUS_REQUEST.name()); - badMessage.setContent("malformed content"); - user1.send("default", badMessage); - - final WebSocketMessage response = user1.getNextMessage("default"); - assertEquals("Received malformed content.", JsonPath.read(response.getContent(), "$.description")); - } - - @Test - public void shouldRejectMalformedContentInUserEnteredMessage() throws Exception { - final WebSocketMessage badMessage = new WebSocketMessage(); - badMessage.setEntity(SymbolPresenceServiceEnum.SYMBOL_PRESENCE_SERVICE.name()); - badMessage.setType(SymbolPresenceServiceEnum.USER_ENTERED.name()); - badMessage.setContent("malformed content"); - user1.send("default", badMessage); - - final WebSocketMessage response = user1.getNextMessage("default"); - assertEquals("Received malformed content.", JsonPath.read(response.getContent(), "$.description")); - } - - @Test - public void shouldRejectMalformedContentInUserLeftMessage() throws Exception { - final WebSocketMessage badMessage = new WebSocketMessage(); - badMessage.setEntity(SymbolPresenceServiceEnum.SYMBOL_PRESENCE_SERVICE.name()); - badMessage.setType(SymbolPresenceServiceEnum.USER_LEFT.name()); - badMessage.setContent("malformed content"); - user1.send("default", badMessage); - - final WebSocketMessage response = user1.getNextMessage("default"); - assertEquals("Received malformed content.", JsonPath.read(response.getContent(), "$.description")); - } - - @Test - public void shouldRejectStatusRequestWithNonExistentProject() throws Exception { - user1.send("default", symbolPresenceServiceWSMessages.requestStatus(Collections.singletonList(-1L))); - - final WebSocketMessage response = user1.getNextMessage("default"); - assertEquals("Project with id -1 not found.", JsonPath.read(response.getContent(), "$.description")); - } - - private List getLocks(String content, int projectId, int symbolGroupId) { - return JsonPath.read(content, "$.['" + projectId + "'].groups.['" + symbolGroupId + "'].locks"); - } - - private String getUsername(String content, int projectId, int symbolId) { - return JsonPath.read(content, "$.['" + projectId + "'].symbols.['" + symbolId + "'].username"); - } - - private String getGroupsAsString(String content, int projectId) { - return JsonPath.read(content, "$.['" + projectId + "'].groups").toString(); - } - - private String getSymbolsAsString(String content, int projectId) { - return JsonPath.read(content, "$.['" + projectId + "'].symbols").toString(); - } - - private Long getTimestamp(String content, int projectId, int symbolId) { - return JsonPath.read(content, "$.['" + projectId + "'].symbols.['" + symbolId + "'].timestamp"); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/WebSocketServiceIT.java b/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/WebSocketServiceIT.java deleted file mode 100644 index fb3c4c0f9..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/WebSocketServiceIT.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.websocket; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.jayway.jsonpath.JsonPath; -import de.learnlib.alex.integrationtests.resources.AbstractResourceIT; -import de.learnlib.alex.integrationtests.websocket.util.WebSocketUser; -import de.learnlib.alex.websocket.entities.WebSocketMessage; -import de.learnlib.alex.websocket.services.enums.WebSocketServiceEnum; -import java.util.List; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class WebSocketServiceIT extends AbstractResourceIT { - - private WebSocketUser user1; - - private WebSocketUser user2; - - @BeforeEach - public void pre() throws Exception { - user1 = new WebSocketUser("user1", client, port); - user2 = new WebSocketUser("user2", client, port); - } - - @AfterEach - @Override - public void post() throws Exception { - List.of(user1, user2).forEach(u -> { - u.clearMessagesInAllSessions(); - u.forceDisconnectAll(); - }); - - super.post(); - } - - @Test - public void shouldRejectNullEntity() throws Exception { - final var badMessage = new WebSocketMessage(); - badMessage.setType("SOME_TYPE"); - badMessage.setContent("SOME_CONTENT"); - - user1.send("default", badMessage); - final var response = user1.getNextMessage("default"); - assertEquals("Received malformed WebSocketMessage.", getDescription(response.getContent())); - } - - @Test - public void shouldRejectNullType() throws Exception { - final var badMessage = new WebSocketMessage(); - badMessage.setEntity("SOME_ENTITY"); - badMessage.setContent("SOME_CONTENT"); - - final var response = user1.sendAndReceive("default", badMessage); - assertEquals("Received malformed WebSocketMessage.", getDescription(response.getContent())); - } - - @Test - public void shouldCatchSystemReservedEntity() throws Exception { - final var badMessage = new WebSocketMessage(); - badMessage.setType("SOME_TYPE"); - badMessage.setEntity(WebSocketServiceEnum.WEBSOCKET_SERVICE_INTERNAL.name()); - badMessage.setContent("SOME_CONTENT"); - - final var response = user1.sendAndReceive("default", badMessage); - assertEquals("Received system reserved entity type.", getDescription(response.getContent())); - } - - @Test - public void shouldIgnoreForcedDisconnectsWithNonMatchingUserIds() { - client.target(baseUrl() + "/ws/disconnect").request() - .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) - .header(HttpHeaders.AUTHORIZATION, user1.getJwt()) - .post(Entity.json("{\"sessionId\":\"" + user2.getSessionId("default") + "\"}")); - - assertTrue(user2.getSession("default").isConnected()); - assertTrue(user1.getSession("default").isConnected()); - } - - @Test - public void shouldPropagateLogoutCheck() throws Exception { - user1.connectNewSession("otherSession"); - - final var message = new WebSocketMessage(); - message.setEntity(WebSocketServiceEnum.WEBSOCKET_SERVICE.name()); - message.setType(WebSocketServiceEnum.LOGOUT.name()); - user1.send("default", message); - - final var response = user1.getNextMessage("otherSession"); - assertEquals(WebSocketServiceEnum.LOGOUT_CHECK.name(), response.getType()); - } - - private String getDescription(String content) { - return JsonPath.read(content, "$.description"); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/util/BlockingQueueSessionHandler.java b/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/util/BlockingQueueSessionHandler.java deleted file mode 100644 index aaf2f31ef..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/util/BlockingQueueSessionHandler.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.websocket.util; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.alex.websocket.entities.WebSocketMessage; -import de.learnlib.alex.websocket.services.enums.WebSocketServiceEnum; -import java.lang.reflect.Type; -import java.util.concurrent.BlockingQueue; -import javax.annotation.Nonnull; -import org.springframework.messaging.simp.stomp.StompHeaders; -import org.springframework.messaging.simp.stomp.StompSession; -import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter; - -class BlockingQueueSessionHandler extends StompSessionHandlerAdapter { - - private final BlockingQueue queue; - - private final ObjectMapper objectMapper = new ObjectMapper(); - - public BlockingQueueSessionHandler(BlockingQueue queue) { - this.queue = queue; - } - - @Override - public void afterConnected(StompSession session, @Nonnull StompHeaders connectedHeaders) { - session.subscribe("/user/queue", this); - session.subscribe("/user/queue/error", this); - - final WebSocketMessage msg = new WebSocketMessage(); - msg.setEntity(WebSocketServiceEnum.WEBSOCKET_SERVICE.name()); - msg.setType(WebSocketServiceEnum.REQUEST_SESSION_ID.name()); - - try { - session.send("/app/send/event", objectMapper.writeValueAsString(msg)); - } catch (JsonProcessingException e) { - e.printStackTrace(); - } - } - - @Override - public Type getPayloadType(StompHeaders headers) { - return WebSocketMessage.class; - } - - @Override - public void handleFrame(StompHeaders headers, Object payload) { - queue.offer((WebSocketMessage) payload); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/util/ProjectPresenceServiceWSMessages.java b/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/util/ProjectPresenceServiceWSMessages.java deleted file mode 100644 index d11aa217d..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/util/ProjectPresenceServiceWSMessages.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.websocket.util; - -import de.learnlib.alex.websocket.entities.WebSocketMessage; -import de.learnlib.alex.websocket.services.enums.ProjectPresenceServiceEnum; -import java.util.List; - -public class ProjectPresenceServiceWSMessages extends WSMessages { - - public WebSocketMessage requestStatus(List projectIds) { - final var msg = new WebSocketMessage(); - msg.setEntity(ProjectPresenceServiceEnum.PROJECT_PRESENCE_SERVICE.name()); - msg.setType(ProjectPresenceServiceEnum.STATUS_REQUEST.name()); - msg.setContent(createContent(projectIds)); - return msg; - } - - public WebSocketMessage userEnteredProject(long projectId) { - final var msg = new WebSocketMessage(); - msg.setEntity(ProjectPresenceServiceEnum.PROJECT_PRESENCE_SERVICE.name()); - msg.setType(ProjectPresenceServiceEnum.USER_ENTERED.name()); - msg.setContent(createContent(projectId)); - return msg; - } - - public WebSocketMessage userLeftProject(long projectId) { - final var msg = new WebSocketMessage(); - msg.setEntity(ProjectPresenceServiceEnum.PROJECT_PRESENCE_SERVICE.name()); - msg.setType(ProjectPresenceServiceEnum.USER_LEFT.name()); - msg.setContent(createContent(projectId)); - return msg; - } - - private String createContent(long projectId) { - final var content = objectMapper.createObjectNode(); - content.put("projectId", projectId); - return content.toString(); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/util/SymbolPresenceServiceWSMessages.java b/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/util/SymbolPresenceServiceWSMessages.java deleted file mode 100644 index cd5c4d39d..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/util/SymbolPresenceServiceWSMessages.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.websocket.util; - -import de.learnlib.alex.websocket.entities.WebSocketMessage; -import de.learnlib.alex.websocket.services.enums.SymbolPresenceServiceEnum; -import java.util.List; - -public class SymbolPresenceServiceWSMessages extends WSMessages { - - public WebSocketMessage requestStatus(List projectIds) { - final var msg = new WebSocketMessage(); - msg.setEntity(SymbolPresenceServiceEnum.SYMBOL_PRESENCE_SERVICE.name()); - msg.setType(SymbolPresenceServiceEnum.STATUS_REQUEST.name()); - msg.setContent(createContent(projectIds)); - return msg; - } - - public WebSocketMessage userEnteredSymbol(long projectId, long symbolId) { - final var msg = new WebSocketMessage(); - msg.setEntity(SymbolPresenceServiceEnum.SYMBOL_PRESENCE_SERVICE.name()); - msg.setType(SymbolPresenceServiceEnum.USER_ENTERED.name()); - msg.setContent(createContent(projectId, symbolId)); - return msg; - } - - public WebSocketMessage userLeftSymbol(long projectId, long symbolId) { - final var msg = new WebSocketMessage(); - msg.setEntity(SymbolPresenceServiceEnum.SYMBOL_PRESENCE_SERVICE.name()); - msg.setType(SymbolPresenceServiceEnum.USER_LEFT.name()); - msg.setContent(createContent(projectId, symbolId)); - return msg; - } - - private String createContent(long projectId, long symbolId) { - final var content = objectMapper.createObjectNode(); - content.put("projectId", projectId); - content.put("symbolId", symbolId); - return content.toString(); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/util/TestPresenceServiceWSMessages.java b/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/util/TestPresenceServiceWSMessages.java deleted file mode 100644 index 77e142576..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/util/TestPresenceServiceWSMessages.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.websocket.util; - -import de.learnlib.alex.websocket.entities.WebSocketMessage; -import de.learnlib.alex.websocket.services.enums.TestPresenceServiceEnum; -import java.util.List; - -public class TestPresenceServiceWSMessages extends WSMessages { - - public WebSocketMessage requestStatus(List projectIds) { - final var msg = new WebSocketMessage(); - msg.setEntity(TestPresenceServiceEnum.TEST_PRESENCE_SERVICE.name()); - msg.setType(TestPresenceServiceEnum.STATUS_REQUEST.name()); - msg.setContent(createContent(projectIds)); - return msg; - } - - public WebSocketMessage userEnteredTest(long projectId, long testId) { - final var msg = new WebSocketMessage(); - msg.setEntity(TestPresenceServiceEnum.TEST_PRESENCE_SERVICE.name()); - msg.setType(TestPresenceServiceEnum.USER_ENTERED.name()); - msg.setContent(createContent(projectId, testId)); - return msg; - } - - public WebSocketMessage userLeftTest(long projectId, long testId) { - final var msg = new WebSocketMessage(); - msg.setEntity(TestPresenceServiceEnum.TEST_PRESENCE_SERVICE.name()); - msg.setType(TestPresenceServiceEnum.USER_LEFT.name()); - msg.setContent(createContent(projectId, testId)); - return msg; - } - - private String createContent(long projectId, long testId) { - final var content = objectMapper.createObjectNode(); - content.put("projectId", projectId); - content.put("testId", testId); - return content.toString(); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/util/WSMessages.java b/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/util/WSMessages.java deleted file mode 100644 index 252da1063..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/util/WSMessages.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.websocket.util; - -import com.fasterxml.jackson.databind.ObjectMapper; -import java.util.List; - -public abstract class WSMessages { - - protected final ObjectMapper objectMapper = new ObjectMapper(); - - protected String createContent(List projectIds) { - final var projects = objectMapper.createArrayNode(); - projectIds.forEach(projects::add); - final var content = objectMapper.createObjectNode(); - content.set("projectIds", projects); - return content.toString(); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/util/WebSocketUser.java b/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/util/WebSocketUser.java deleted file mode 100644 index 2e0cb32f5..000000000 --- a/backend/src/test/java/de/learnlib/alex/integrationtests/websocket/util/WebSocketUser.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.integrationtests.websocket.util; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.jayway.jsonpath.JsonPath; -import de.learnlib.alex.integrationtests.resources.api.UserApi; -import de.learnlib.alex.websocket.entities.WebSocketMessage; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.LinkedBlockingDeque; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.Entity; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import org.springframework.messaging.converter.MappingJackson2MessageConverter; -import org.springframework.messaging.simp.stomp.StompHeaders; -import org.springframework.messaging.simp.stomp.StompSession; -import org.springframework.web.socket.client.standard.StandardWebSocketClient; -import org.springframework.web.socket.messaging.WebSocketStompClient; -import org.springframework.web.socket.sockjs.client.SockJsClient; -import org.springframework.web.socket.sockjs.client.WebSocketTransport; - -public class WebSocketUser { - - /** Default poll time in seconds */ - private final int DEFAULT_POLL_TIME = 3; - - private String wsUrl() { - return "ws://localhost:" + port + "/rest/ws/stomp"; - } - - private String baseUrl() { - return "http://localhost/" + port + "/rest"; - } - - private final Client client; - private final int port; - - private final long userId; - private final String jwt; - - private final WebSocketStompClient stompClient; - private final StompHeaders headers; - - private final Map sessions; - private final Map sessionIds; - private final Map> messages; - - private final ObjectMapper objectMapper; - - public WebSocketUser(String username, Client client, int port) throws InterruptedException, ExecutionException, TimeoutException, IOException, URISyntaxException { - this.client = client; - this.port = port; - - this.sessions = new HashMap<>(); - this.sessionIds = new HashMap<>(); - this.messages = new HashMap<>(); - this.objectMapper = new ObjectMapper(); - - final UserApi userApi = new UserApi(client, port); - final Response res = userApi.create("{\"email\":\"" + username + "@test.de\",\"username\":\"" + username + "\",\"password\":\"test\"}"); - this.userId = Integer.toUnsignedLong(JsonPath.read(res.readEntity(String.class), "id")); - this.jwt = userApi.login(username + "@test.de", "test"); - - this.stompClient = new WebSocketStompClient( - new SockJsClient(Collections.singletonList( - new WebSocketTransport( - new StandardWebSocketClient())))); - - this.stompClient.setMessageConverter(new MappingJackson2MessageConverter()); - - headers = new StompHeaders(); - headers.add("Authorization", this.jwt); - - this.connectNewSession("default"); - } - - public long getUserId() { - return userId; - } - - public String getJwt() { - return jwt; - } - - public String getSessionId(String sessionName) { - return this.sessionIds.get(sessionName); - } - - public StompSession getSession(String sessionName) { - return this.sessions.get(sessionName); - } - - public void connectNewSession(String sessionName) throws URISyntaxException, InterruptedException, ExecutionException, TimeoutException, IOException { - final var messageQueue = new LinkedBlockingDeque(); - this.messages.put(sessionName, messageQueue); - - final var sessionHandler = new BlockingQueueSessionHandler(messageQueue); - final var stompSession = this.stompClient.connect(new URI(wsUrl()), null, headers, sessionHandler) - .get(10, TimeUnit.SECONDS); - - this.sessions.put(sessionName, stompSession); - - final var response = getNextMessage(sessionName); - final var content = (ObjectNode) objectMapper.readTree(response.getContent()); - this.sessionIds.put(sessionName, content.get("sessionId").asText()); - } - - public void send(String sessionName, WebSocketMessage message) throws JsonProcessingException { - this.sessions.get(sessionName).send("/app/send/event", objectMapper.writeValueAsString(message)); - } - - public WebSocketMessage sendAndReceive(String sessionName, WebSocketMessage message) throws JsonProcessingException, InterruptedException { - send(sessionName, message); - return getNextMessage(sessionName); - } - - public int getAmountOfMessages(String sessionName) { - return this.messages.get(sessionName).size(); - } - - public WebSocketMessage getNextMessage(String sessionName) throws InterruptedException { - return this.messages.get(sessionName).poll(DEFAULT_POLL_TIME, TimeUnit.SECONDS); - } - - public void clearMessagesInAllSessions() { - this.messages.forEach((k,v) -> v.clear()); - } - - public void forceDisconnect(String sessionName) { - client.target(baseUrl() + "/ws/disconnect").request() - .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) - .header(HttpHeaders.AUTHORIZATION, this.jwt) - .post(Entity.json("{\"sessionId\":\"" + this.sessionIds.get(sessionName) + "\"}")); - } - - public void forceDisconnectAll() { - this.sessionIds.keySet().forEach(this::forceDisconnect); - } - - public boolean assertNumberOfMessages(List sessions, List expectedAmountOfMessages) { - assertEquals(sessions.size(), expectedAmountOfMessages.size()); - var valid = true; - for (int i = 0; i < sessions.size(); i++) { - valid &= getAmountOfMessages(sessions.get(i)) == expectedAmountOfMessages.get(i); - } - return valid; - } - - public boolean assertNumberOfMessages(String session, Integer expectedAmountOfMessages) { - return assertNumberOfMessages(List.of(session), List.of(expectedAmountOfMessages)); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/learning/dao/LearnerResultDAOTest.java b/backend/src/test/java/de/learnlib/alex/learning/dao/LearnerResultDAOTest.java deleted file mode 100644 index c94f6c6ba..000000000 --- a/backend/src/test/java/de/learnlib/alex/learning/dao/LearnerResultDAOTest.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.dao; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.verify; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.common.exceptions.NotFoundException; -import de.learnlib.alex.data.dao.ProjectDAO; -import de.learnlib.alex.data.entities.Project; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.repositories.ProjectRepository; -import de.learnlib.alex.learning.entities.LearnerResult; -import de.learnlib.alex.learning.repositories.LearnerResultRepository; -import de.learnlib.alex.learning.repositories.LearnerResultStepRepository; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import javax.persistence.EntityManager; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class LearnerResultDAOTest { - - private static final long USER_ID = 21L; - private static final long PROJECT_ID = 42L; - private static final int RESULTS_AMOUNT = 3; - - @Mock - private ProjectDAO projectDAO; - - @Mock - private LearnerResultRepository learnerResultRepository; - - @Mock - private LearnerResultStepRepository learnerResultStepRepository; - - @Mock - private ProjectRepository projectRepository; - - @Mock - private LearnerSetupDAO learnerSetupDAO; - - @Mock - private EntityManager entityManager; - - @Mock - private LearnerResultStepDAO learnerResultStepDAO; - - private LearnerResultDAO learnerResultDAO; - - @BeforeEach - public void setUp() { - learnerResultDAO = new LearnerResultDAO( - projectDAO, - learnerResultRepository, - learnerResultStepRepository, - projectRepository, - learnerSetupDAO, - entityManager, - learnerResultStepDAO - ); - } - - @Test - public void shouldSaveAValidLearnerResult() { - User user = new User(); - user.setId(USER_ID); - - LearnerResult result = createLearnerResultsList().get(0); - - given(projectDAO.getByID(user, PROJECT_ID)).willReturn(result.getProject()); - given(learnerResultRepository.findHighestTestNo(PROJECT_ID)).willReturn(1L); - given(learnerResultRepository.save(result)).willReturn(result); - - learnerResultDAO.create(user, result.getProject().getId(), result); - - verify(learnerResultRepository).save(result); - assertEquals(2L, (long) result.getTestNo()); - } - - @Test - public void shouldGetAllResultsOfOneProject() { - User user = new User(); - - List results = createLearnerResultsList(); - given(learnerResultRepository.findByProject_Id(PROJECT_ID)).willReturn(results); - List resultsFromDAO = learnerResultDAO.getAll(user, PROJECT_ID); - - assertEquals(results.size(), resultsFromDAO.size()); - for (LearnerResult r : resultsFromDAO) { - assertTrue(results.contains(r)); - } - } - - @Test - public void ensureThatGettingAllResultsReturnsAnEmptyListIfNoLearnerResultCouldBeFound() { - User user = new User(); - - given(learnerResultRepository.findByProject_Id(PROJECT_ID)) - .willReturn(Collections.emptyList()); - - List results = learnerResultDAO.getAll(user, PROJECT_ID); - assertEquals(results.size(), 0); - } - - @Test - public void shouldGetMultipleResults() { - final var user = new User(); - - final var project = new Project(); - project.setId(PROJECT_ID); - - List results = createLearnerResultsList(); - - - List testNos = Arrays.asList(0L, 1L, 2L); - - given(projectDAO.getByID(user, PROJECT_ID)).willReturn(project); - given(learnerResultRepository.findByProject_IdAndTestNoIn(PROJECT_ID, testNos)).willReturn(results); - - List resultsFromDAO = learnerResultDAO.getAll(user, PROJECT_ID, testNos); - - assertEquals(results.size(), resultsFromDAO.size()); - for (LearnerResult r : resultsFromDAO) { - assertTrue(results.contains(r)); - } - } - - @Test - public void ensureThatGettingANonExistingResultThrowsAnException() { - User user = new User(); - - given(learnerResultRepository.findOneByProject_IdAndTestNo(PROJECT_ID, 0L)) - .willReturn(null); - - assertThrows(NotFoundException.class, () -> learnerResultDAO.getByTestNo(user, PROJECT_ID, 0L)); - } - - @Test - public void shouldDeleteMultipleResults() { - List testNos = Arrays.asList(0L, 1L); - - given(learnerResultRepository.deleteByProject_IdAndTestNoIn(PROJECT_ID, testNos)).willReturn(2L); - - learnerResultDAO.deleteByTestNos(new User(USER_ID), PROJECT_ID, testNos); - - verify(learnerResultRepository).deleteByProject_IdAndTestNoIn(PROJECT_ID, testNos); - } - - private List createLearnerResultsList() { - List results = new ArrayList<>(); - for (int i = 0; i < RESULTS_AMOUNT; i++) { - LearnerResult r = new LearnerResult(); - Project project = new Project(PROJECT_ID); - Symbol s1 = new Symbol(); - s1.setId(1L); - s1.setProject(project); - Symbol s2 = new Symbol(); - s2.setId(2L); - s2.setProject(project); - r.setProject(project); - results.add(r); - } - return results; - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/learning/entities/LearnerResumeConfigurationTest.java b/backend/src/test/java/de/learnlib/alex/learning/entities/LearnerResumeConfigurationTest.java deleted file mode 100644 index 825cab07a..000000000 --- a/backend/src/test/java/de/learnlib/alex/learning/entities/LearnerResumeConfigurationTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.mock; - -import de.learnlib.alex.learning.entities.learnlibproxies.eqproxies.AbstractEquivalenceOracleProxy; -import de.learnlib.alex.learning.entities.learnlibproxies.eqproxies.MealyRandomWordsEQOracleProxy; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.BDDMockito; - -public class LearnerResumeConfigurationTest { - - private LearnerResumeConfiguration configuration; - - @BeforeEach - public void setUp() { - configuration = new LearnerResumeConfiguration(); - configuration.setStepNo(1); - } - - @Test - public void shouldSayThatItIsAValidConfigurationIfItIsOne() { - configuration.setEqOracle(new MealyRandomWordsEQOracleProxy()); - configuration.checkConfiguration(); - } - - @Test - public void ensureThatAnExceptionIsThrownIfNoEqOracleIsGiven() { - configuration.setEqOracle(null); - assertThrows(IllegalArgumentException.class, () -> configuration.checkConfiguration()); - } - - @Test - public void ensureThatAnExceptionIsThrownIfAnInvalidEqOracleIsGiven() { - AbstractEquivalenceOracleProxy eqOracle = mock(AbstractEquivalenceOracleProxy.class); - BDDMockito.willThrow(IllegalArgumentException.class).given(eqOracle).checkParameters(); - configuration.setEqOracle(eqOracle); - assertThrows(IllegalArgumentException.class, () -> configuration.checkConfiguration()); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/learning/entities/SeparatingWordTest.java b/backend/src/test/java/de/learnlib/alex/learning/entities/SeparatingWordTest.java deleted file mode 100644 index 43010b894..000000000 --- a/backend/src/test/java/de/learnlib/alex/learning/entities/SeparatingWordTest.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities; - -import com.fasterxml.jackson.databind.ObjectMapper; -import net.automatalib.words.Word; -import org.junit.jupiter.api.Test; -import org.skyscreamer.jsonassert.JSONAssert; - -public class SeparatingWordTest { - - private final ObjectMapper om = new ObjectMapper(); - - @Test - public void shouldSerializeEmptySeparatingWordCorrectly() throws Exception { - final SeparatingWord sw = new SeparatingWord(); - final String swString = om.writeValueAsString(sw); - final String expectedSwString = "{\"input\":[],\"output1\":[],\"output2\":[]}"; - JSONAssert.assertEquals(expectedSwString, swString, true); - } - - @Test - public void shouldSerializeSeparatingWordCorrectly() throws Exception { - final SeparatingWord sw = new SeparatingWord(Word.fromLetter("a"), Word.fromLetter("1"), Word.fromLetter("2")); - final String swString = om.writeValueAsString(sw); - final String expectedSwString = "{\"input\":[\"a\"],\"output1\":[\"1\"],\"output2\":[\"2\"]}"; - JSONAssert.assertEquals(expectedSwString, swString, true); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/learning/entities/algorithms/DHCTest.java b/backend/src/test/java/de/learnlib/alex/learning/entities/algorithms/DHCTest.java deleted file mode 100644 index 33b404a94..000000000 --- a/backend/src/test/java/de/learnlib/alex/learning/entities/algorithms/DHCTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.algorithms; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.mock; - -import de.learnlib.api.algorithm.LearningAlgorithm; -import de.learnlib.oracle.membership.SULOracle; -import net.automatalib.words.Alphabet; -import net.automatalib.words.impl.GrowingMapAlphabet; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class DHCTest { - - private DHC algorithm; - - @BeforeEach - public void setUp() { - algorithm = new DHC(); - } - - @Test - public void shouldCreateCorrectLearner() { - Alphabet sigma = new GrowingMapAlphabet<>(); - SULOracle oracle = mock(SULOracle.class); - algorithm.createLearner(sigma, oracle); - } - - @Test - public void shouldNeverReturnInternalData() { - LearningAlgorithm.MealyLearner learner = mock(LearningAlgorithm.MealyLearner.class); - assertEquals(algorithm.getInternalData(learner), ""); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/learning/entities/algorithms/DiscriminationTreeTest.java b/backend/src/test/java/de/learnlib/alex/learning/entities/algorithms/DiscriminationTreeTest.java deleted file mode 100644 index da249d93c..000000000 --- a/backend/src/test/java/de/learnlib/alex/learning/entities/algorithms/DiscriminationTreeTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.algorithms; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -import de.learnlib.algorithms.discriminationtree.hypothesis.HState; -import de.learnlib.algorithms.discriminationtree.mealy.DTLearnerMealy; -import de.learnlib.api.algorithm.LearningAlgorithm; -import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDTNode; -import de.learnlib.datastructure.discriminationtree.model.AbstractWordBasedDiscriminationTree; -import de.learnlib.oracle.membership.SULOracle; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; -import net.automatalib.words.impl.GrowingMapAlphabet; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class DiscriminationTreeTest { - - private DiscriminationTree algorithm; - - @BeforeEach - public void setUp() { - algorithm = new DiscriminationTree(); - } - - @Test - public void shouldCreateCorrectLearner() { - Alphabet sigma = new GrowingMapAlphabet<>(); - sigma.add("a"); - sigma.add("b"); - SULOracle oracle = mock(SULOracle.class); - - algorithm.createLearner(sigma, oracle); - } - - @Test - public void shouldReturnCorrectInternalData() { - DTLearnerMealy learner = createDTLearnerMock(); - - String json = algorithm.getInternalData(learner); - assertEquals("{\"discriminator\": \"null\", \"children\": []}", json); - } - - private DTLearnerMealy createDTLearnerMock() { - AbstractWordBasedDiscriminationTree, HState, Void, String>> tree; - tree = mock(AbstractWordBasedDiscriminationTree.class); - given(tree.getRoot()).willReturn(mock(AbstractWordBasedDTNode.class)); - DTLearnerMealy learner = mock(DTLearnerMealy.class); - given(learner.getDiscriminationTree()).willReturn(tree); - return learner; - } - - @Test - public void shouldFailToCreateInternalDataFromWrongAlgorithmType() { - LearningAlgorithm.MealyLearner learner = mock(LearningAlgorithm.MealyLearner.class); - assertThrows(IllegalArgumentException.class, () -> algorithm.getInternalData(learner)); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/learning/entities/algorithms/LStarTest.java b/backend/src/test/java/de/learnlib/alex/learning/entities/algorithms/LStarTest.java deleted file mode 100644 index 9dcce3f1a..000000000 --- a/backend/src/test/java/de/learnlib/alex/learning/entities/algorithms/LStarTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.algorithms; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -import de.learnlib.algorithms.lstar.mealy.ExtensibleLStarMealy; -import de.learnlib.api.algorithm.LearningAlgorithm; -import de.learnlib.datastructure.observationtable.ObservationTable; -import de.learnlib.oracle.membership.SULOracle; -import net.automatalib.words.Alphabet; -import net.automatalib.words.impl.GrowingMapAlphabet; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class LStarTest { - - private static final String TEST_TABLE = "+==+" + System.lineSeparator() - + "| |" + System.lineSeparator() - + "+==+" + System.lineSeparator() - + "+==+" + System.lineSeparator() - + "+==+" + System.lineSeparator(); - - private LStar algorithm; - - @BeforeEach - public void setUp() { - algorithm = new LStar(); - } - - @Test - public void shouldCreateCorrectLearner() { - Alphabet sigma = new GrowingMapAlphabet<>(); - sigma.add("a"); - sigma.add("b"); - SULOracle oracle = mock(SULOracle.class); - - algorithm.createLearner(sigma, oracle); - } - - @Test - public void shouldReturnCorrectInternalData() { - ExtensibleLStarMealy learner = createLearnerMock(); - - String json = algorithm.getInternalData(learner); - assertEquals(TEST_TABLE, json); - } - - private ExtensibleLStarMealy createLearnerMock() { - ObservationTable observationTable = mock(ObservationTable.class); - ExtensibleLStarMealy learner = mock(ExtensibleLStarMealy.class); - given(learner.getObservationTable()).willReturn(observationTable); - return learner; - } - - @Test - public void shouldFailToCreateInternalDataFromWrongAlgorithmType() { - LearningAlgorithm.MealyLearner learner = mock(LearningAlgorithm.MealyLearner.class); - assertThrows(IllegalArgumentException.class, () -> algorithm.getInternalData(learner)); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/learning/entities/algorithms/TTTTest.java b/backend/src/test/java/de/learnlib/alex/learning/entities/algorithms/TTTTest.java deleted file mode 100644 index 7eeb48101..000000000 --- a/backend/src/test/java/de/learnlib/alex/learning/entities/algorithms/TTTTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.algorithms; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -import de.learnlib.algorithms.ttt.base.AbstractBaseDTNode; -import de.learnlib.algorithms.ttt.base.BaseTTTDiscriminationTree; -import de.learnlib.algorithms.ttt.mealy.TTTLearnerMealy; -import de.learnlib.api.algorithm.LearningAlgorithm; -import de.learnlib.oracle.membership.SULOracle; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; -import net.automatalib.words.impl.GrowingMapAlphabet; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class TTTTest { - - private TTT algorithm; - - @BeforeEach - public void setUp() { - algorithm = new TTT(); - } - - @Test - public void shouldCreateCorrectLearner() { - Alphabet sigma = new GrowingMapAlphabet<>(); - sigma.add("a"); - sigma.add("b"); - SULOracle oracle = mock(SULOracle.class); - - algorithm.createLearner(sigma, oracle); - } - - @Test - public void shouldReturnCorrectInternalData() { - TTTLearnerMealy learner = createLearnerMock(); - - String json = algorithm.getInternalData(learner); - assertEquals("{\"discriminator\": \"null\", \"children\": []}", json); - } - - private TTTLearnerMealy createLearnerMock() { - BaseTTTDiscriminationTree> tree = mock(BaseTTTDiscriminationTree.class); - given(tree.getRoot()).willReturn(mock(AbstractBaseDTNode.class)); - TTTLearnerMealy learner = mock(TTTLearnerMealy.class); - given(learner.getDiscriminationTree()).willReturn(tree); - return learner; - } - - @Test - public void shouldFailToCreateInternalDataFromWrongAlgorithmType() { - LearningAlgorithm.MealyLearner learner = mock(LearningAlgorithm.MealyLearner.class); - assertThrows(IllegalArgumentException.class, () -> algorithm.getInternalData(learner)); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/learning/entities/learnlibproxies/CompactMealyMachineProxyTest.java b/backend/src/test/java/de/learnlib/alex/learning/entities/learnlibproxies/CompactMealyMachineProxyTest.java deleted file mode 100644 index 057705a10..000000000 --- a/backend/src/test/java/de/learnlib/alex/learning/entities/learnlibproxies/CompactMealyMachineProxyTest.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.learnlibproxies; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; - -import com.fasterxml.jackson.databind.ObjectMapper; -import net.automatalib.automata.transducers.impl.compact.CompactMealy; -import net.automatalib.util.automata.Automata; -import net.automatalib.words.Alphabet; -import net.automatalib.words.impl.Alphabets; -import org.junit.jupiter.api.Test; -import org.skyscreamer.jsonassert.JSONAssert; - -public class CompactMealyMachineProxyTest { - - private final Alphabet alphabet = Alphabets.fromArray("a", "b"); - - @Test - public void shouldSerializeCorrectly() throws Exception { - final CompactMealy mealy = createMealy(); - final CompactMealyMachineProxy mealyProxy = CompactMealyMachineProxy.createFrom(mealy, alphabet); - - final ObjectMapper om = new ObjectMapper(); - final String mealyString = om.writeValueAsString(mealyProxy); - final String expectedMealyString = "{\"nodes\":[0,1]" - + ",\"initNode\":0" - + ",\"edges\":[" - + " {\"from\":0,\"input\":\"a\",\"to\":0,\"output\":\"1\"}" - + ",{\"from\":0,\"input\":\"b\",\"to\":1,\"output\":\"2\"}" - + ",{\"from\":1,\"input\":\"a\",\"to\":1,\"output\":\"1\"}" - + ",{\"from\":1,\"input\":\"b\",\"to\":0,\"output\":\"2\"}]}"; - - JSONAssert.assertEquals(expectedMealyString, mealyString, true); - } - - @Test - public void shouldGetCorrectInputAlphabet() { - final CompactMealy mealy = createMealy(); - final CompactMealyMachineProxy mealyProxy = CompactMealyMachineProxy.createFrom(mealy, alphabet); - final Alphabet alph = mealyProxy.createAlphabet(); - assertEquals(alphabet, alph); - } - - @Test - public void shouldCreateCorrectCompactMealyFromProxy() { - final CompactMealy mealy = createMealy(); - final CompactMealyMachineProxy mealyProxy = CompactMealyMachineProxy.createFrom(mealy, alphabet); - - final Alphabet alph = mealyProxy.createAlphabet(); - final CompactMealy mealy1 = mealyProxy.createMealyMachine(alph); - - assertNull(Automata.findSeparatingWord(mealy1, mealy, alph)); - } - - private CompactMealy createMealy() { - final CompactMealy mealy = new CompactMealy<>(alphabet); - final int s0 = mealy.addState(); - final int s1 = mealy.addState(); - mealy.setInitialState(s0); - mealy.setTransition(s0, "a", s0, "1"); - mealy.setTransition(s1, "b", s0, "2"); - mealy.setTransition(s1, "a", s1, "1"); - mealy.setTransition(s0, "b", s1, "2"); - return mealy; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/learning/entities/learnlibproxies/DefaultQueryProxyTest.java b/backend/src/test/java/de/learnlib/alex/learning/entities/learnlibproxies/DefaultQueryProxyTest.java deleted file mode 100644 index 7107ea511..000000000 --- a/backend/src/test/java/de/learnlib/alex/learning/entities/learnlibproxies/DefaultQueryProxyTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.learnlibproxies; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import com.fasterxml.jackson.databind.ObjectMapper; -import de.learnlib.api.query.DefaultQuery; -import net.automatalib.words.Word; -import org.junit.jupiter.api.Test; -import org.skyscreamer.jsonassert.JSONAssert; - -public class DefaultQueryProxyTest { - - private final ObjectMapper om = new ObjectMapper(); - - @Test - public void shouldSerializeCorrectly() throws Exception { - final DefaultQuery> query = createQuery(); - final DefaultQueryProxy queryProxy = DefaultQueryProxy.createFrom(query); - final String queryString = om.writeValueAsString(queryProxy); - final String expectedQueryString = "{\"prefix\":[],\"suffix\":[\"a\",\"b\"],\"output\":[\"1\",\"2\"]}"; - - JSONAssert.assertEquals(expectedQueryString, queryString, true); - } - - @Test - public void shouldCreateQueryFromProxy() { - final DefaultQuery> query = createQuery(); - final DefaultQueryProxy queryProxy = DefaultQueryProxy.createFrom(query); - - assertEquals(query, queryProxy.createDefaultQuery()); - } - - private DefaultQuery> createQuery() { - final DefaultQuery> query = new DefaultQuery<>(Word.fromSymbols("a", "b")); - query.answer(Word.fromSymbols("1", "2")); - return query; - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/CompleteExplorationEQOracleProxyTest.java b/backend/src/test/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/CompleteExplorationEQOracleProxyTest.java deleted file mode 100644 index 1cfcfec38..000000000 --- a/backend/src/test/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/CompleteExplorationEQOracleProxyTest.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.learnlibproxies.eqproxies; - -import static org.junit.jupiter.api.Assertions.assertThrows; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class CompleteExplorationEQOracleProxyTest { - - public static final int MAX_DEPTH = 10; - private CompleteExplorationEQOracleProxy eqOracle; - - @BeforeEach - public void setUp() { - eqOracle = new CompleteExplorationEQOracleProxy(); - eqOracle.setMinDepth(1); - eqOracle.setMaxDepth(MAX_DEPTH); - } - - @Test - public void ensureThatIfTheParametersAreValidNoExceptionWillBeThrown() { - eqOracle.checkParameters(); // nothing should happen - } - - @Test - public void ensureThatAnExceptionIsThrownIfMinDepthIsGreaterThanMaxDepth() { - eqOracle.setMinDepth(MAX_DEPTH); - eqOracle.setMaxDepth(1); - - assertThrows(IllegalArgumentException.class, () -> eqOracle.checkParameters()); - } - - @Test - public void ensureThatAnExceptionIsThrownIfMinDepthIsNegative() { - eqOracle.setMinDepth(-1); - - assertThrows(IllegalArgumentException.class, () -> eqOracle.checkParameters()); - } - - @Test - public void ensureThatAnExceptionIsThrownIfMaxDepthIsNegative() { - eqOracle.setMaxDepth(-1); - - assertThrows(IllegalArgumentException.class, () -> eqOracle.checkParameters()); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/MealyRandomWordsEQOracleProxyTest.java b/backend/src/test/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/MealyRandomWordsEQOracleProxyTest.java deleted file mode 100644 index 5ea50c788..000000000 --- a/backend/src/test/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/MealyRandomWordsEQOracleProxyTest.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.learnlibproxies.eqproxies; - -import static org.junit.jupiter.api.Assertions.assertThrows; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class MealyRandomWordsEQOracleProxyTest { - - public static final int MAX_LENGTH = 10; - public static final int MAX_NO_OF_TESTS = 10; - public static final int SEED = 42; - - private MealyRandomWordsEQOracleProxy eqOracle; - - @BeforeEach - public void setUp() { - eqOracle = new MealyRandomWordsEQOracleProxy(); - eqOracle.setMinLength(1); - eqOracle.setMaxLength(MAX_LENGTH); - eqOracle.setMaxNoOfTests(MAX_NO_OF_TESTS); - eqOracle.setSeed(SEED); - } - - @Test - public void ensureThatIfTheParametersAreValidNoExceptionWillBeThrown() { - eqOracle.checkParameters(); // nothing should happen - } - - @Test - public void ensureThatAnExceptionIsThrownIfMinLengthIsGreaterThanMaxLength() { - eqOracle.setMinLength(MAX_LENGTH); - eqOracle.setMaxLength(1); - assertThrows(IllegalArgumentException.class, () -> eqOracle.checkParameters()); - } - - @Test - public void ensureThatAnExceptionIsThrownIfMinLengthIsNegative() { - eqOracle.setMinLength(-1); - assertThrows(IllegalArgumentException.class, () -> eqOracle.checkParameters()); - } - - @Test - public void ensureThatAnExceptionIsThrownIfMaxLengthIsNegative() { - eqOracle.setMaxLength(-1); - assertThrows(IllegalArgumentException.class, () -> eqOracle.checkParameters()); - } - - @Test - public void ensureThatAnExceptionIsThrownIfNoAmountOfTestIsGiven() { - eqOracle.setMaxNoOfTests(0); - assertThrows(IllegalArgumentException.class, () -> eqOracle.checkParameters()); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/SampleEQOracleProxyTest.java b/backend/src/test/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/SampleEQOracleProxyTest.java deleted file mode 100644 index 5e6a119f8..000000000 --- a/backend/src/test/java/de/learnlib/alex/learning/entities/learnlibproxies/eqproxies/SampleEQOracleProxyTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.entities.learnlibproxies.eqproxies; - -import com.fasterxml.jackson.databind.ObjectMapper; -import java.util.ArrayList; -import java.util.List; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.skyscreamer.jsonassert.JSONAssert; - -public class SampleEQOracleProxyTest { - - private SampleEQOracleProxy eqOracle; - - @BeforeEach - public void setUp() { - List counterExample1 = new ArrayList<>(); - counterExample1.add(new SampleEQOracleProxy.InputOutputPair("input1", "output1")); - counterExample1.add(new SampleEQOracleProxy.InputOutputPair("input2", "output2")); - List counterExample2 = new ArrayList<>(); - counterExample2.add(new SampleEQOracleProxy.InputOutputPair("input3", "output3")); - counterExample2.add(new SampleEQOracleProxy.InputOutputPair("input4", "output4")); - - eqOracle = new SampleEQOracleProxy(); - eqOracle.addCounterExample(counterExample1); - eqOracle.addCounterExample(counterExample2); - } - - @Test - public void shouldCreateCorrectJSON() throws Exception { - ObjectMapper mapper = new ObjectMapper(); - String actualJSON = mapper.writeValueAsString(eqOracle); - - String expectedJSON = "{\"batchSize\":20,\"type\":\"sample\",\"counterExamples\":[" - + "[{\"input\":\"input1\",\"output\":\"output1\"}," - + "{\"input\":\"input2\",\"output\":\"output2\"}]," - + "[{\"input\":\"input3\",\"output\":\"output3\"}" - + ",{\"input\":\"input4\",\"output\":\"output4\"}]" - + "]}"; - JSONAssert.assertEquals(expectedJSON, actualJSON, true); - } - - @Test - public void ensureThatIfTheParametersAreValidNoExceptionWillBeThrown() { - eqOracle.checkParameters(); // nothing should happen - } -} diff --git a/backend/src/test/java/de/learnlib/alex/learning/services/QueryMonitorOracleTest.java b/backend/src/test/java/de/learnlib/alex/learning/services/QueryMonitorOracleTest.java deleted file mode 100644 index 5be93e9df..000000000 --- a/backend/src/test/java/de/learnlib/alex/learning/services/QueryMonitorOracleTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import de.learnlib.alex.learning.services.oracles.QueryMonitorOracle; -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.api.query.DefaultQuery; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import net.automatalib.words.Word; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -public class QueryMonitorOracleTest { - - private MembershipOracle> mqOracle; - - private QueryMonitorOracle monitorOracle; - - private int count1; - private int count2; - - @BeforeEach - public void before() { - this.mqOracle = Mockito.mock(MembershipOracle.class); - Mockito.doNothing().when(mqOracle).processQueries(Mockito.anyCollection()); - - count1 = 0; - count2 = 0; - - final QueryMonitorOracle.QueryProcessingListener preListener = queries -> count1 = queries.size(); - final QueryMonitorOracle.QueryProcessingListener postListener = queries -> count2 = queries.size(); - - this.monitorOracle = new QueryMonitorOracle<>(mqOracle); - this.monitorOracle.addPreProcessingListener(preListener); - this.monitorOracle.addPostProcessingListener(postListener); - } - - @Test - public void shouldDoNothingIfNoQueriesAreProcessed() { - monitorOracle.processQueries(Collections.emptyList()); - Mockito.verify(mqOracle, Mockito.never()).processQueries(Mockito.anyCollection()); - assertEquals(0, count1); - assertEquals(0, count2); - } - - @Test - public void shouldProcessPreAndPostListeners() { - final List>> queries = new ArrayList<>(); - queries.add(new DefaultQuery<>(Word.fromSymbols("a", "b"))); - queries.add(new DefaultQuery<>(Word.fromSymbols("b", "c"))); - - monitorOracle.processQueries(queries); - Mockito.verify(mqOracle, Mockito.times(1)).processQueries(queries); - assertEquals(2, count1); - assertEquals(2, count2); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/learning/services/SymbolMapperTest.java b/backend/src/test/java/de/learnlib/alex/learning/services/SymbolMapperTest.java deleted file mode 100644 index 845d7f2af..000000000 --- a/backend/src/test/java/de/learnlib/alex/learning/services/SymbolMapperTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.data.entities.SymbolInputParameter; -import de.learnlib.alex.data.entities.SymbolParameter; -import de.learnlib.alex.data.entities.SymbolParameterValue; -import java.util.Arrays; -import java.util.Collections; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class SymbolMapperTest { - - private ParameterizedSymbol ps1; - - private ParameterizedSymbol ps2; - - private SymbolMapper sm; - - @BeforeEach - public void before() { - final Symbol s1 = new Symbol(); - s1.setName("s1"); - s1.setId(1L); - - this.ps1 = new ParameterizedSymbol(); - this.ps1.setSymbol(s1); - - final Symbol s2 = new Symbol(); - s2.setName("s2"); - s2.setId(2L); - - final SymbolInputParameter input = new SymbolInputParameter(); - input.setName("in"); - input.setSymbol(s2); - input.setParameterType(SymbolParameter.ParameterType.STRING); - s2.setInputs(Collections.singletonList(input)); - - this.ps2 = new ParameterizedSymbol(); - this.ps2.setSymbol(s2); - - final SymbolParameterValue value = new SymbolParameterValue(); - value.setParameter(input); - value.setValue("test"); - ps2.setParameterValues(Collections.singletonList(value)); - - this.sm = new SymbolMapper(Arrays.asList(ps1, ps2)); - } - - @Test - public void shouldBeForkable() { - assertTrue(sm.canFork()); - } - - @Test - public void shouldMapInputStringToCorrectSymbol() { - assertEquals(ps1, sm.mapInput("s1")); - assertEquals(ps2, sm.mapInput("s2 ")); - } - - @Test - public void shouldMapOutputCorrectly() { - final ExecuteResult result = new ExecuteResult(); - result.setSuccess(true); - result.setMessage("ok"); - - assertEquals("Ok (ok)", sm.mapOutput(result)); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/learning/services/connectors/ConnectorContextHandlerTest.java b/backend/src/test/java/de/learnlib/alex/learning/services/connectors/ConnectorContextHandlerTest.java deleted file mode 100644 index 1263d2c4e..000000000 --- a/backend/src/test/java/de/learnlib/alex/learning/services/connectors/ConnectorContextHandlerTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services.connectors; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import de.learnlib.alex.data.entities.ExecuteResult; -import de.learnlib.alex.data.entities.ParameterizedSymbol; -import de.learnlib.alex.data.entities.ProjectEnvironment; -import de.learnlib.alex.data.entities.Symbol; -import de.learnlib.alex.learning.exceptions.LearnerException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class ConnectorContextHandlerTest { - - private ConnectorContextHandler handler; - - @Mock - private ParameterizedSymbol resetSymbol; - - @BeforeEach - public void setUp() { - Symbol symbol = new Symbol(); - symbol.setId(1L); - given(resetSymbol.getSymbol()).willReturn(symbol); - } - - @Test - public void shouldCreateTheContextCorrectly() { - given(resetSymbol.execute(any(ConnectorManager.class))).willReturn(new ExecuteResult(true)); - - ConnectorManager connectorManager = new ConnectorManager(new ProjectEnvironment()); - VariableStoreConnector connector1 = mock(VariableStoreConnector.class); - CounterStoreConnector connector2 = mock(CounterStoreConnector.class); - connectorManager.addConnector(connector1); - connectorManager.addConnector(connector2); - - handler = new ConnectorContextHandler(connectorManager, resetSymbol, null); - - assertEquals(connector1, connectorManager.getConnector(connector1.getClass())); - assertEquals(connector2, connectorManager.getConnector(connector2.getClass())); - - handler.createContext(); - verify(connector1).reset(); - verify(connector2).reset(); - verify(resetSymbol).execute(any(ConnectorManager.class)); - } - - @Test - public void shouldThrowAnExceptionIfTheResetSymbolExecutionFailed() { - given(resetSymbol.execute(any(ConnectorManager.class))).willReturn(new ExecuteResult(false)); - - handler = new ConnectorContextHandler(createConnectorManager(), resetSymbol, null); - assertThrows(LearnerException.class, () -> handler.createContext()); // should fail - } - - private ConnectorManager createConnectorManager() { - ConnectorManager connectorManager = new ConnectorManager(new ProjectEnvironment()); - Connector connector1 = mock(VariableStoreConnector.class); - Connector connector2 = mock(CounterStoreConnector.class); - connectorManager.addConnector(connector1); - connectorManager.addConnector(connector2); - return connectorManager; - } -} diff --git a/backend/src/test/java/de/learnlib/alex/learning/services/connectors/ConnectorManagerTest.java b/backend/src/test/java/de/learnlib/alex/learning/services/connectors/ConnectorManagerTest.java deleted file mode 100644 index 3d152e87d..000000000 --- a/backend/src/test/java/de/learnlib/alex/learning/services/connectors/ConnectorManagerTest.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.alex.learning.services.connectors; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import de.learnlib.alex.data.entities.ProjectEnvironment; -import org.junit.jupiter.api.Test; - - -public class ConnectorManagerTest { - - @Test - public void shouldDisposeAllConnectors() { - Connector connector1 = mock(WebSiteConnector.class); - Connector connector2 = mock(WebServiceConnector.class); - - ConnectorManager manager = new ConnectorManager(new ProjectEnvironment()); - manager.addConnector(connector1); - manager.addConnector(connector2); - - manager.dispose(); - - verify(connector1).dispose(); - verify(connector2).dispose(); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/learning/services/connectors/CounterStoreConnectorTest.java b/backend/src/test/java/de/learnlib/alex/learning/services/connectors/CounterStoreConnectorTest.java deleted file mode 100644 index e1c2e8533..000000000 --- a/backend/src/test/java/de/learnlib/alex/learning/services/connectors/CounterStoreConnectorTest.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services.connectors; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.mock; - -import de.learnlib.alex.auth.entities.User; -import de.learnlib.alex.data.dao.CounterDAO; -import de.learnlib.alex.data.entities.Counter; -import de.learnlib.alex.data.entities.Project; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class CounterStoreConnectorTest { - - private static final Long PROJECT_ID = 10L; - private static final String COUNTER_NAME = "counter"; - private static final Integer COUNTER_VALUE = 42; - - private CounterStoreConnector connector; - - @BeforeEach - public void setUp() { - connector = new CounterStoreConnector(mock(CounterDAO.class), mock(User.class), mock(Project.class), new ArrayList<>()); - } - - @Test - public void shouldInitializeTheInternalStoreCorrectly() { - Counter c1 = new Counter(); - c1.setName("c1"); - c1.setValue(3); - - Counter c2 = new Counter(); - c2.setName("c2"); - c1.setValue(4); - - List counters = new ArrayList<>(Arrays.asList(c1, c2)); - - CounterStoreConnector connector = new CounterStoreConnector(mock(CounterDAO.class), mock(User.class), mock(Project.class), counters); - - assertEquals(connector.get(c1.getName()), c1.getValue()); - assertEquals(connector.get(c2.getName()), c2.getValue()); - } - - @Test - public void shouldSetTheCounterValue() { - connector.set(PROJECT_ID, COUNTER_NAME, COUNTER_VALUE); - assertNotNull(connector.get(COUNTER_NAME)); - assertEquals(connector.get(COUNTER_NAME), COUNTER_VALUE); - } - - @Test - public void shouldIncrementTheCounterValue() { - connector.set(PROJECT_ID, COUNTER_NAME, COUNTER_VALUE); - connector.incrementBy(PROJECT_ID, COUNTER_NAME, 5); - assertEquals(connector.get(COUNTER_NAME), Integer.valueOf(COUNTER_VALUE + 5)); - } - - @Test - public void shouldFailToIncrementTheCounterIfNotDefined() { - assertThrows(IllegalStateException.class, () -> connector.incrementBy(PROJECT_ID, COUNTER_NAME, 5)); - } - - @Test - public void shouldFailToGetTheCounterIfNotDefined() { - assertThrows(IllegalStateException.class, () -> connector.get(COUNTER_NAME)); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/learning/services/connectors/VariableStoreConnectorTest.java b/backend/src/test/java/de/learnlib/alex/learning/services/connectors/VariableStoreConnectorTest.java deleted file mode 100644 index c5a36afb7..000000000 --- a/backend/src/test/java/de/learnlib/alex/learning/services/connectors/VariableStoreConnectorTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.learning.services.connectors; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class VariableStoreConnectorTest { - - private static final String VARIABLE_NAME = "variable"; - private static final String VARIABLE_VALUE = "foobar"; - - private VariableStoreConnector connector; - - @BeforeEach - public void setUp() { - connector = new VariableStoreConnector(); - } - - @Test - public void shouldCorrectlyStoreAVariable() { - connector.set(VARIABLE_NAME, VARIABLE_VALUE); - - assertNotNull(connector.get(VARIABLE_NAME)); - assertEquals(VARIABLE_VALUE, connector.get(VARIABLE_NAME)); - } - - @Test - public void shouldResetTheStorage() { - connector.set(VARIABLE_NAME, VARIABLE_VALUE); - connector.reset(); - } - - @Test - public void shouldFailWhenFetchingANotSetVariable() { - assertThrows(IllegalStateException.class, () -> connector.get(VARIABLE_NAME)); - } - -} diff --git a/backend/src/test/java/de/learnlib/alex/modelchecking/entities/LtsCheckingConfigTest.java b/backend/src/test/java/de/learnlib/alex/modelchecking/entities/LtsCheckingConfigTest.java deleted file mode 100644 index 1425dbab9..000000000 --- a/backend/src/test/java/de/learnlib/alex/modelchecking/entities/LtsCheckingConfigTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.entities; - -import static org.junit.jupiter.api.Assertions.assertThrows; - -import java.util.Arrays; -import java.util.Collections; -import javax.validation.ValidationException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class LtsCheckingConfigTest { - - private LtsCheckingConfig config; - - @BeforeEach - public void before() { - config = new LtsCheckingConfig(); - - final LtsFormula f1 = new LtsFormula(); - f1.setFormula("true"); - final LtsFormula f2 = new LtsFormula(); - f2.setFormula("true"); - - config.setFormulas(Arrays.asList(f1, f2)); - config.setLearnerResultId(1L); - config.setStepNo(1); - } - - @Test - public void shouldThrowExceptionIfResultIdIsNull() { - config.setLearnerResultId(null); - assertThrows(ValidationException.class, () -> config.validate()); - } - - @Test - public void shouldThrowExceptionIfResultIdIsLessThanZero() { - config.setLearnerResultId(-1L); - assertThrows(ValidationException.class, () -> config.validate()); - } - - @Test - public void shouldThrowExceptionIfStepNoIsNull() { - config.setStepNo(null); - assertThrows(ValidationException.class, () -> config.validate()); - } - - @Test - public void shouldThrowExceptionIfStepNoIsLessThanOne() { - config.setStepNo(0); - assertThrows(ValidationException.class, () -> config.validate()); - } - - @Test - public void shouldThrowExceptionIsFormulasAreEmpty() { - config.setFormulas(Collections.emptyList()); - assertThrows(ValidationException.class, () -> config.validate()); - } - - @Test - public void shouldThrowExceptionIfMinUnfoldsIsLessThanZero() { - config.setMinUnfolds(-1); - assertThrows(ValidationException.class, () -> config.validate()); - } - - @Test - public void shouldThrowExceptionIfMultiplierIsLessThanZero() { - config.setMultiplier(-1.0); - assertThrows(ValidationException.class, () -> config.validate()); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/modelchecking/entities/LtsCheckingResultTest.java b/backend/src/test/java/de/learnlib/alex/modelchecking/entities/LtsCheckingResultTest.java deleted file mode 100644 index 55d69d5bd..000000000 --- a/backend/src/test/java/de/learnlib/alex/modelchecking/entities/LtsCheckingResultTest.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2015 - 2022 TU Dortmund - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.learnlib.alex.modelchecking.entities; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import net.automatalib.words.Word; -import org.junit.jupiter.api.Test; - -public class LtsCheckingResultTest { - - @Test - public void shouldOnlyPassIfPrefixAndLoopAreEmpty() { - LtsCheckingResult result = new LtsCheckingResult(new LtsFormula(), 1L, 1L); - assertTrue(result.isPassed()); - - result = new LtsCheckingResult(new LtsFormula(), 1L, 1L, Word.fromSymbols("a"), Word.epsilon()); - assertFalse(result.isPassed()); - - result = new LtsCheckingResult(new LtsFormula(), 1L, 1L, Word.epsilon(), Word.fromSymbols("a")); - assertFalse(result.isPassed()); - - result = new LtsCheckingResult(new LtsFormula(), 1L, 1L, Word.fromSymbols("b"), Word.fromSymbols("a")); - assertFalse(result.isPassed()); - } -} diff --git a/backend/src/test/java/de/learnlib/alex/settings/dao/SettingsDAOTest.java b/backend/src/test/java/de/learnlib/alex/settings/dao/SettingsDAOTest.java deleted file mode 100644 index a1d4a7fb6..000000000 --- a/backend/src/test/java/de/learnlib/alex/settings/dao/SettingsDAOTest.java +++ /dev/null @@ -1,68 +0,0 @@ -package de.learnlib.alex.settings.dao; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import de.learnlib.alex.settings.entities.Settings; -import de.learnlib.alex.settings.repositories.SettingsRepository; -import javax.validation.ValidationException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class SettingsDAOTest { - - @Mock - private SettingsRepository settingsRepository; - - private SettingsDAO settingsDAO; - - @BeforeEach - public void setUp() { - settingsDAO = new SettingsDAO(settingsRepository); - } - - @Test - public void shouldCreateTheSettings() { - Settings settings = new Settings(); - settingsDAO.create(settings); - verify(settingsRepository).save(settings); - } - - @Test - public void shouldCreateTheSettingsOnlyOnce() { - Settings settings = new Settings(); - settingsDAO.create(settings); - given(settingsRepository.count()).willReturn(1L); - assertThrows(ValidationException.class, () -> settingsDAO.create(settings)); - } - - @Test - public void shouldGetTheSettings() { - Settings settings = new Settings(); - given(settingsRepository.get()).willReturn(settings); - Settings s = settingsDAO.get(); - assertEquals(settings, s); - } - - @Test - public void shouldReturnNullForGetIfNotCreated() { - assertNull(settingsDAO.get()); - } - - @Test - public void shouldUpdateTheSettings() { - Settings settings = new Settings(); - settingsDAO.create(settings); - settingsDAO.update(settings); - verify(settingsRepository, times(2)).save(settings); // only 1 x creation & 1 x update should call save - } - -} diff --git a/backend/src/test/resources/actions/ExecuteSymbolTestData.json b/backend/src/test/resources/actions/ExecuteSymbolTestData.json deleted file mode 100644 index 732c349b9..000000000 --- a/backend/src/test/resources/actions/ExecuteSymbolTestData.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "executeSymbol", - "symbolToExecute": 1 -} diff --git a/backend/src/test/resources/actions/StoreSymbolActions/AssertCounterTestData.json b/backend/src/test/resources/actions/StoreSymbolActions/AssertCounterTestData.json deleted file mode 100644 index a966e6748..000000000 --- a/backend/src/test/resources/actions/StoreSymbolActions/AssertCounterTestData.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "assertCounter", - "name": "counter", - "value": 42, - "operator": "equal" -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/StoreSymbolActions/AssertVariableTestData.json b/backend/src/test/resources/actions/StoreSymbolActions/AssertVariableTestData.json deleted file mode 100644 index 7058aaad9..000000000 --- a/backend/src/test/resources/actions/StoreSymbolActions/AssertVariableTestData.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "assertVariable", - "name": "variable", - "value": "foobar", - "regexp": true -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/StoreSymbolActions/IncrementCounterTestData.json b/backend/src/test/resources/actions/StoreSymbolActions/IncrementCounterTestData.json deleted file mode 100644 index 2264110c1..000000000 --- a/backend/src/test/resources/actions/StoreSymbolActions/IncrementCounterTestData.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "incrementCounter", - "name": "counter" -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/StoreSymbolActions/SetCounterTestData.json b/backend/src/test/resources/actions/StoreSymbolActions/SetCounterTestData.json deleted file mode 100644 index f892cda2d..000000000 --- a/backend/src/test/resources/actions/StoreSymbolActions/SetCounterTestData.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "type": "setCounter", - "name": "counter", - "value": 42 -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/StoreSymbolActions/SetVariableByCookieTestData.json b/backend/src/test/resources/actions/StoreSymbolActions/SetVariableByCookieTestData.json deleted file mode 100644 index 6959471ab..000000000 --- a/backend/src/test/resources/actions/StoreSymbolActions/SetVariableByCookieTestData.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "setVariableByCookie", - "name": "foobar", - "value": "cookie", - "cookieType": "web" -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/StoreSymbolActions/SetVariableByHTMLElementTestData.json b/backend/src/test/resources/actions/StoreSymbolActions/SetVariableByHTMLElementTestData.json deleted file mode 100644 index 23b9c5dac..000000000 --- a/backend/src/test/resources/actions/StoreSymbolActions/SetVariableByHTMLElementTestData.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "setVariableByHTML", - "name": "variable", - "node": { - "selector": "foobar", - "type": "CSS" - } -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/StoreSymbolActions/SetVariableByJSONAttributeTestData.json b/backend/src/test/resources/actions/StoreSymbolActions/SetVariableByJSONAttributeTestData.json deleted file mode 100644 index 44f6cef44..000000000 --- a/backend/src/test/resources/actions/StoreSymbolActions/SetVariableByJSONAttributeTestData.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "type": "setVariableByJSON", - "name": "variable", - "value": "foobar" -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/StoreSymbolActions/SetVariableByNodeAttributeTestData.json b/backend/src/test/resources/actions/StoreSymbolActions/SetVariableByNodeAttributeTestData.json deleted file mode 100644 index 67ed4f45b..000000000 --- a/backend/src/test/resources/actions/StoreSymbolActions/SetVariableByNodeAttributeTestData.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "type": "setVariableByNodeAttribute", - "name": "variable", - "node": { - "selector": "node", - "type": "CSS" - }, - "attribute": "attribute" -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/StoreSymbolActions/SetVariableTestData.json b/backend/src/test/resources/actions/StoreSymbolActions/SetVariableTestData.json deleted file mode 100644 index 622202dca..000000000 --- a/backend/src/test/resources/actions/StoreSymbolActions/SetVariableTestData.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "type": "setVariable", - "name": "variable", - "value": "foobar" -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/WaitTestData.json b/backend/src/test/resources/actions/WaitTestData.json deleted file mode 100644 index 6e7afe747..000000000 --- a/backend/src/test/resources/actions/WaitTestData.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "wait", - "duration": 1000 -} diff --git a/backend/src/test/resources/actions/restsymbolactions/CallActionTestData.json b/backend/src/test/resources/actions/restsymbolactions/CallActionTestData.json deleted file mode 100644 index 1391a151e..000000000 --- a/backend/src/test/resources/actions/restsymbolactions/CallActionTestData.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "rest_call", - "method": "GET", - "url": "http://example.com/api", - "headers": { - "X-MyHeader": "Foobar, Bar" - }, - "cookies": { - "cookie": "Lorem Ipsum" - }, - "data": "{}" -} diff --git a/backend/src/test/resources/actions/restsymbolactions/CheckAttributeExistsTestData.json b/backend/src/test/resources/actions/restsymbolactions/CheckAttributeExistsTestData.json deleted file mode 100644 index b31cb75a9..000000000 --- a/backend/src/test/resources/actions/restsymbolactions/CheckAttributeExistsTestData.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "rest_checkAttributeExists", - "attribute": "object.attribute" -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/restsymbolactions/CheckAttributeTypeTestData.json b/backend/src/test/resources/actions/restsymbolactions/CheckAttributeTypeTestData.json deleted file mode 100644 index 817c1b9f5..000000000 --- a/backend/src/test/resources/actions/restsymbolactions/CheckAttributeTypeTestData.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "type": "rest_checkAttributeType", - "attribute": "object.attribute", - "jsonType": "STRING" -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/restsymbolactions/CheckAttributeValueTestData.json b/backend/src/test/resources/actions/restsymbolactions/CheckAttributeValueTestData.json deleted file mode 100644 index 0fede0a21..000000000 --- a/backend/src/test/resources/actions/restsymbolactions/CheckAttributeValueTestData.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "rest_checkAttributeValue", - "attribute": "object.attribute", - "value": "FooBar Lorem", - "regexp": true -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/restsymbolactions/CheckForTextTestData.json b/backend/src/test/resources/actions/restsymbolactions/CheckForTextTestData.json deleted file mode 100644 index 574b84f62..000000000 --- a/backend/src/test/resources/actions/restsymbolactions/CheckForTextTestData.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "type": "rest_checkForText", - "value": "Lorem Ipsum", - "regexp": true -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/restsymbolactions/CheckHeaderFieldTestData.json b/backend/src/test/resources/actions/restsymbolactions/CheckHeaderFieldTestData.json deleted file mode 100644 index 44ce46927..000000000 --- a/backend/src/test/resources/actions/restsymbolactions/CheckHeaderFieldTestData.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "rest_checkHeaderField", - "key": "Key", - "value": "Value", - "regexp": true -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/restsymbolactions/CheckStatusTestData.json b/backend/src/test/resources/actions/restsymbolactions/CheckStatusTestData.json deleted file mode 100644 index 6aed8ad4a..000000000 --- a/backend/src/test/resources/actions/restsymbolactions/CheckStatusTestData.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "rest_checkStatus", - "status": 200 -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/websymbolactions/CheckNodeTestData.json b/backend/src/test/resources/actions/websymbolactions/CheckNodeTestData.json deleted file mode 100644 index 1690b8504..000000000 --- a/backend/src/test/resources/actions/websymbolactions/CheckNodeTestData.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "web_checkForNode", - "node": { - "selector": "#node", - "type": "CSS" - } -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/websymbolactions/CheckPageTitleTestData.json b/backend/src/test/resources/actions/websymbolactions/CheckPageTitleTestData.json deleted file mode 100644 index 09eda881e..000000000 --- a/backend/src/test/resources/actions/websymbolactions/CheckPageTitleTestData.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "type": "web_checkPageTitle", - "title": "Awesome Title No. {{#title}}", - "regexp": true -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/websymbolactions/CheckTextTestData.json b/backend/src/test/resources/actions/websymbolactions/CheckTextTestData.json deleted file mode 100644 index b245c450d..000000000 --- a/backend/src/test/resources/actions/websymbolactions/CheckTextTestData.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "web_checkForText", - "value": "Lorem Ipsum", - "node": { - "selector": "document", - "type": "CSS" - } -} diff --git a/backend/src/test/resources/actions/websymbolactions/ClearTestData.json b/backend/src/test/resources/actions/websymbolactions/ClearTestData.json deleted file mode 100644 index 91867c6fb..000000000 --- a/backend/src/test/resources/actions/websymbolactions/ClearTestData.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "web_clear", - "node": { - "selector": "#node", - "type": "CSS" - } -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/websymbolactions/ClickLinkTestData.json b/backend/src/test/resources/actions/websymbolactions/ClickLinkTestData.json deleted file mode 100644 index 111d5a5da..000000000 --- a/backend/src/test/resources/actions/websymbolactions/ClickLinkTestData.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "web_clickLinkByText", - "value": "Click Me", - "node": { - "selector": "body", - "type": "CSS" - } -} diff --git a/backend/src/test/resources/actions/websymbolactions/ClickTestData.json b/backend/src/test/resources/actions/websymbolactions/ClickTestData.json deleted file mode 100644 index fd8553a68..000000000 --- a/backend/src/test/resources/actions/websymbolactions/ClickTestData.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "web_click", - "node": { - "selector": "#node", - "type": "CSS" - }, - "doubleClick": false -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/websymbolactions/ExecuteScriptTestData.json b/backend/src/test/resources/actions/websymbolactions/ExecuteScriptTestData.json deleted file mode 100644 index 22a6aea76..000000000 --- a/backend/src/test/resources/actions/websymbolactions/ExecuteScriptTestData.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "web_executeScript", - "script": "document.write('hello')" -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/websymbolactions/FillTestData.json b/backend/src/test/resources/actions/websymbolactions/FillTestData.json deleted file mode 100644 index 834097c2b..000000000 --- a/backend/src/test/resources/actions/websymbolactions/FillTestData.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "web_fill", - "node": { - "selector": "#input", - "type": "CSS" - }, - "value": "Lorem Ipsum" -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/websymbolactions/GotoTestData.json b/backend/src/test/resources/actions/websymbolactions/GotoTestData.json deleted file mode 100644 index 098324e60..000000000 --- a/backend/src/test/resources/actions/websymbolactions/GotoTestData.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "type": "web_goto", - "url": "http://example.com/", - "baseUrl": "Base" -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/websymbolactions/MoveMouseTestData.json b/backend/src/test/resources/actions/websymbolactions/MoveMouseTestData.json deleted file mode 100644 index 1ea5d187a..000000000 --- a/backend/src/test/resources/actions/websymbolactions/MoveMouseTestData.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "type": "web_moveMouse", - "node": { - "selector": "#node", - "type": "CSS" - }, - "offsetX": 0, - "offsetY": 0 -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/websymbolactions/SelectTestData.json b/backend/src/test/resources/actions/websymbolactions/SelectTestData.json deleted file mode 100644 index ebcb7332f..000000000 --- a/backend/src/test/resources/actions/websymbolactions/SelectTestData.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "type": "web_select", - "node": { - "selector": "#node", - "type": "CSS" - }, - "value": "Lorem Ipsum", - "selectBy": "text" -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/websymbolactions/SubmitTestData.json b/backend/src/test/resources/actions/websymbolactions/SubmitTestData.json deleted file mode 100644 index b65f44258..000000000 --- a/backend/src/test/resources/actions/websymbolactions/SubmitTestData.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "web_submit", - "node": { - "selector": "#node", - "type": "CSS" - } -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/websymbolactions/WaitForNodeTestData.json b/backend/src/test/resources/actions/websymbolactions/WaitForNodeTestData.json deleted file mode 100644 index ae542605e..000000000 --- a/backend/src/test/resources/actions/websymbolactions/WaitForNodeTestData.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "type": "web_waitForNode", - "node": { - "selector": "#node", - "type": "CSS" - }, - "waitCriterion": "added", - "maxWaitTime": 5 -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/websymbolactions/WaitForTitleTestData.json b/backend/src/test/resources/actions/websymbolactions/WaitForTitleTestData.json deleted file mode 100644 index f55b82943..000000000 --- a/backend/src/test/resources/actions/websymbolactions/WaitForTitleTestData.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "web_waitForTitle", - "value": "#node", - "waitCriterion": "contains", - "maxWaitTime": 60 -} \ No newline at end of file diff --git a/backend/src/test/resources/actions/websymbolactions/WebSymbolTestData.json b/backend/src/test/resources/actions/websymbolactions/WebSymbolTestData.json deleted file mode 100644 index 2086450fe..000000000 --- a/backend/src/test/resources/actions/websymbolactions/WebSymbolTestData.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "id": 1, - "name": "Test Symbol", - "steps": [ - { - "type": "action", - "action": { - "type": "web_checkForNode", - "node": { - "selector": "#node", - "type": "CSS" - } - } - }, - { - "type": "action", - "action": { - "type": "web_checkForText", - "value": "Lorem Ipsum" - } - }, - { - "type": "action", - "action": { - "type": "web_clear", - "node": { - "selector": "#node", - "type": "CSS" - } - } - }, - { - "type": "action", - "action": { - "type": "web_click", - "node": { - "selector": "#node", - "type": "CSS" - } - } - }, - { - "type": "action", - "action": { - "type": "web_fill", - "node": { - "selector": "#input", - "type": "CSS" - }, - "value": "Lorem Ipsum" - } - }, - { - "type": "action", - "action": { - "type": "web_submit", - "node": { - "selector": "#node", - "type": "CSS" - } - } - }, - { - "type": "action", - "action": { - "type": "wait", - "duration": 1000 - } - } - ] -} diff --git a/backend/src/test/resources/application.yml b/backend/src/test/resources/application.yml deleted file mode 100644 index 48049e86c..000000000 --- a/backend/src/test/resources/application.yml +++ /dev/null @@ -1,40 +0,0 @@ -spring: - jpa: - properties: - hibernate: - jdbc: - lob: - non_contextual_creation: true - hibernate: - ddl-auto: "update" - datasource: - initialization-mode: "always" - platform: "postgres" - url: ${DB_URL} - username: ${DB_USERNAME} - password: ${DB_PASSWORD} - -server: - port: ${alex.port:8000} - compression: - enabled: "true" - mime-types: "text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json" - min-response-size: "1024" - -alex: - filesRootDir: "./target/test-files" - version: "3.0.0" - admin: - email: "admin@alex.example" - password: "admin" - username: "admin" - -selenium: - grid: - host: "selenium-hub" - port: "4444" - -ltsmin: - path: "" - -runtime: "kubernetes" diff --git a/backend/src/test/resources/applicationContext.xml b/backend/src/test/resources/applicationContext.xml deleted file mode 100644 index b9f290f88..000000000 --- a/backend/src/test/resources/applicationContext.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - \ No newline at end of file diff --git a/backend/src/test/resources/core/entities/LearnerResultTestData.json b/backend/src/test/resources/core/entities/LearnerResultTestData.json deleted file mode 100644 index 74d00fbac..000000000 --- a/backend/src/test/resources/core/entities/LearnerResultTestData.json +++ /dev/null @@ -1,132 +0,0 @@ -{ - "algorithm": "TTT", - "browser": "htmlunitdriver", - "comment": "", - "hypothesis": { - "nodes": [ - 0, - 1 - ], - "initNode": 0, - "edges": [ - { - "from": 0, - "input": "0", - "to": 0, - "output": "OK" - }, - { - "from": 0, - "input": "1", - "to": 1, - "output": "OK" - }, - { - "from": 1, - "input": "0", - "to": 1, - "output": "OK" - }, - { - "from": 1, - "input": "1", - "to": 0, - "output": "OK" - } - ] - }, - "project": 3, - "resetSymbol": null, - "sigma": [ - "0", - "1" - ], - "statistics": { - "duration": { - "learner": 0, - "eqOracle": 0, - "total": 0 - }, - "eqsUsed": 0, - "mqsUsed": { - "learner": 0, - "eqOracle": 0, - "total": 0 - }, - "startDate": "1970-01-01T00:00:00.000+00:00", - "symbolsUsed": { - "learner": 0, - "eqOracle": 0, - "total": 0 - } - }, - "steps": [ - { - "counterExample": "", - "eqOracle": { - "type": "random_word", - "minLength": 1, - "maxLength": 5, - "maxNoOfTests": 10, - "seed": 42 - }, - "hypothesis": { - "nodes": [ - 0, - 1 - ], - "initNode": 0, - "edges": [ - { - "from": 0, - "input": "0", - "to": 0, - "output": "OK" - }, - { - "from": 0, - "input": "1", - "to": 1, - "output": "OK" - }, - { - "from": 1, - "input": "0", - "to": 1, - "output": "OK" - }, - { - "from": 1, - "input": "1", - "to": 0, - "output": "OK" - } - ] - }, - "statistics": { - "duration": { - "learner": 0, - "eqOracle": 0, - "total": 0 - }, - "eqsUsed": 0, - "mqsUsed": { - "learner": 0, - "eqOracle": 0, - "total": 0 - }, - "startDate": "1970-01-01T00:00:00.000+00:00", - "symbolsUsed": { - "learner": 0, - "eqOracle": 0, - "total": 0 - } - }, - "stepNo": 0, - "stepsToLearn": 0 - } - ], - "symbols": [], - "testNo": 3, - "user": 3 -} diff --git a/backend/src/test/resources/core/entities/symbol-with-all-misc-actions.json b/backend/src/test/resources/core/entities/symbol-with-all-misc-actions.json deleted file mode 100644 index a8632d5f7..000000000 --- a/backend/src/test/resources/core/entities/symbol-with-all-misc-actions.json +++ /dev/null @@ -1,328 +0,0 @@ -{ - "name": "all general actions", - "description": null, - "successOutput": null, - "inputs": [], - "outputs": [], - "steps": [ - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "assertCounter", - "name": "test", - "value": 5, - "operator": "EQUAL" - }, - "position": 0 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "assertCounter", - "name": "test", - "value": 5, - "operator": "LESS_THAN" - }, - "position": 1 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "assertCounter", - "name": "test", - "value": 5, - "operator": "LESS_OR_EQUAL" - }, - "position": 2 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "assertCounter", - "name": "test", - "value": 5, - "operator": "GREATER_OR_EQUAL" - }, - "position": 3 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "assertCounter", - "name": "test", - "value": 5, - "operator": "GREATER_THAN" - }, - "position": 4 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "assertVariable", - "name": "test", - "value": "test", - "regexp": false - }, - "position": 5 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "assertVariable", - "name": "test", - "value": "test", - "regexp": true - }, - "position": 6 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "incrementCounter", - "name": "test", - "incrementBy": 1 - }, - "position": 7 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "incrementCounter", - "name": "test", - "incrementBy": -1 - }, - "position": 8 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "setCounter", - "name": "test", - "value": "0", - "valueType": "NUMBER" - }, - "position": 9 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "setCounter", - "name": "test", - "value": "test", - "valueType": "VARIABLE" - }, - "position": 10 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "setVariable", - "name": "test", - "value": "test" - }, - "position": 11 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "setVariable", - "name": "test", - "value": "" - }, - "position": 12 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "setVariableByCookie", - "name": "test", - "value": "test", - "cookieType": "WEB" - }, - "position": 13 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "setVariableByCookie", - "name": "test", - "value": "test", - "cookieType": "REST" - }, - "position": 14 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "setVariableByHttpResponse", - "name": "test" - }, - "position": 15 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "setVariableByHTML", - "name": "test", - "node": { - "selector": "#test", - "type": "CSS" - } - }, - "position": 16 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "setVariableByJSON", - "name": "test", - "value": "test" - }, - "position": 17 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "setVariableByNodeAttribute", - "name": "test", - "node": { - "selector": "#test", - "type": "CSS" - }, - "attribute": "test" - }, - "position": 18 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "setVariableByNodeCount", - "name": "test", - "node": { - "selector": "#test", - "type": "CSS" - } - }, - "position": 19 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "setVariableByRegexGroup", - "name": "test", - "regex": "test", - "nthMatch": 1, - "mthGroup": 0 - }, - "position": 20 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "wait", - "duration": 0 - }, - "position": 21 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "wait", - "duration": 1000 - }, - "position": 22 - } - ] -} diff --git a/backend/src/test/resources/core/entities/symbol-with-all-rest-actions.json b/backend/src/test/resources/core/entities/symbol-with-all-rest-actions.json deleted file mode 100644 index a89879e58..000000000 --- a/backend/src/test/resources/core/entities/symbol-with-all-rest-actions.json +++ /dev/null @@ -1,288 +0,0 @@ -{ - "name": "all rest actions", - "description": null, - "successOutput": null, - "inputs": [], - "outputs": [], - "steps": [ - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "rest_checkAttributeExists", - "attribute": "test" - }, - "position": 0 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "rest_checkAttributeType", - "attribute": "test", - "jsonType": "STRING" - }, - "position": 1 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "rest_checkAttributeType", - "attribute": "test", - "jsonType": "ARRAY" - }, - "position": 2 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "rest_checkAttributeType", - "attribute": "test", - "jsonType": "BOOLEAN" - }, - "position": 3 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "rest_checkAttributeType", - "attribute": "test", - "jsonType": "INTEGER" - }, - "position": 4 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "rest_checkAttributeType", - "attribute": "test", - "jsonType": "INTEGER" - }, - "position": 5 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "rest_checkAttributeType", - "attribute": "test", - "jsonType": "OBJECT" - }, - "position": 6 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "rest_checkAttributeType", - "attribute": "test", - "jsonType": "NULL" - }, - "position": 7 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "rest_checkAttributeValue", - "attribute": "test", - "value": "test", - "regexp": false - }, - "position": 8 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "rest_checkAttributeValue", - "attribute": "test", - "value": "test", - "regexp": true - }, - "position": 9 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "rest_checkHeaderField", - "key": "test", - "value": "test", - "regexp": false - }, - "position": 10 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "rest_checkHeaderField", - "key": "test", - "value": "test", - "regexp": true - }, - "position": 11 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "rest_checkStatus", - "status": 200 - }, - "position": 12 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "rest_call", - "method": "GET", - "url": "test", - "data": "{\"test\":\"test\"}", - "cookies": {}, - "headers": {}, - "credentials": { - "name": "", - "password": "" - }, - "timeout": 0, - "baseUrl": "Base" - }, - "position": 13 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "rest_call", - "method": "POST", - "url": "test", - "data": "{\"test\":\"test\"}", - "cookies": {}, - "headers": {}, - "credentials": { - "name": "", - "password": "" - }, - "timeout": 0, - "baseUrl": "Base" - }, - "position": 14 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "rest_call", - "method": "GET", - "url": "test", - "data": null, - "cookies": { - "test": "test" - }, - "headers": { - "test": "test" - }, - "credentials": { - "name": "test", - "password": "test" - }, - "timeout": 0, - "baseUrl": "Base" - }, - "position": 15 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "rest_checkForText", - "value": "test", - "regexp": false - }, - "position": 16 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "rest_checkForText", - "value": "test", - "regexp": true - }, - "position": 17 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "rest_validateJson", - "schema": "{}" - }, - "position": 18 - } - ] -} diff --git a/backend/src/test/resources/core/entities/symbol-with-all-web-actions.json b/backend/src/test/resources/core/entities/symbol-with-all-web-actions.json deleted file mode 100644 index ea1219973..000000000 --- a/backend/src/test/resources/core/entities/symbol-with-all-web-actions.json +++ /dev/null @@ -1,724 +0,0 @@ -{ - "name": "all web actions", - "description": null, - "successOutput": null, - "inputs": [], - "outputs": [], - "steps": [ - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_alertAcceptDismiss", - "action": "ACCEPT" - }, - "position": 0 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_alertAcceptDismiss", - "action": "DISMISS" - }, - "position": 1 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_alertGetText", - "variableName": "test" - }, - "position": 2 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_alertSendKeys", - "text": "test" - }, - "position": 3 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_browser", - "action": "RESTART" - }, - "position": 4 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_browser", - "action": "REFRESH" - }, - "position": 5 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_checkNodeAttributeValue", - "node": { - "selector": "#test", - "type": "CSS" - }, - "attribute": "test", - "value": "test", - "checkMethod": "IS" - }, - "position": 6 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_checkNodeAttributeValue", - "node": { - "selector": "#test", - "type": "CSS" - }, - "attribute": "test", - "value": "test", - "checkMethod": "CONTAINS" - }, - "position": 7 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_checkNodeAttributeValue", - "node": { - "selector": "#test", - "type": "CSS" - }, - "attribute": "test", - "value": "test", - "checkMethod": "MATCHES" - }, - "position": 8 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_checkNodeAttributeValue", - "node": { - "selector": "#test", - "type": "CSS" - }, - "attribute": "test", - "value": "test", - "checkMethod": "MATCHES" - }, - "position": 9 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_checkPageTitle", - "title": "test", - "regexp": false - }, - "position": 10 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_checkPageTitle", - "title": "test", - "regexp": true - }, - "position": 11 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_checkNodeSelected", - "node": { - "selector": "#test", - "type": "CSS" - } - }, - "position": 12 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_clear", - "node": { - "selector": "#test", - "type": "CSS" - } - }, - "position": 13 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_click", - "node": { - "selector": "#test", - "type": "CSS" - }, - "doubleClick": false - }, - "position": 14 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_click", - "node": { - "selector": "#test", - "type": "CSS" - }, - "doubleClick": true - }, - "position": 15 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_clickElementByText", - "node": { - "selector": "body", - "type": "CSS" - }, - "text": "test", - "tagName": "div" - }, - "position": 16 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_clickLinkByText", - "value": "test", - "node": { - "selector": "body", - "type": "CSS" - } - }, - "position": 17 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_executeScript", - "script": "console.log(\"test\")", - "name": null - }, - "position": 18 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_executeScript", - "script": "return \"5\";", - "name": "test" - }, - "position": 19 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_fill", - "node": { - "selector": "#test", - "type": "CSS" - }, - "value": "test" - }, - "position": 20 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_moveMouse", - "node": { - "selector": "#test", - "type": "CSS" - }, - "offsetX": 0, - "offsetY": 0 - }, - "position": 21 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_goto", - "url": "test", - "credentials": { - "name": "", - "password": "" - }, - "baseUrl": "Base" - }, - "position": 22 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_goto", - "url": "test", - "credentials": { - "name": "test", - "password": "test" - }, - "baseUrl": "Base" - }, - "position": 23 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_pressKey", - "node": { - "selector": "#test", - "type": "CSS" - }, - "key": "\\ue001" - }, - "position": 24 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_checkForText", - "value": "test", - "regexp": false, - "node": { - "selector": "document", - "type": "CSS" - } - }, - "position": 25 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_checkForText", - "value": "test", - "regexp": true, - "node": { - "selector": "document", - "type": "CSS" - } - }, - "position": 26 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_checkForNode", - "node": { - "selector": "#test", - "type": "CSS" - } - }, - "position": 27 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_select", - "node": { - "selector": "#test", - "type": "CSS" - }, - "value": "test", - "selectBy": "TEXT" - }, - "position": 28 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_select", - "node": { - "selector": "#test", - "type": "CSS" - }, - "value": "test", - "selectBy": "VALUE" - }, - "position": 29 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_select", - "node": { - "selector": "#test", - "type": "CSS" - }, - "value": "1", - "selectBy": "INDEX" - }, - "position": 30 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_submit", - "node": { - "selector": "#test", - "type": "CSS" - } - }, - "position": 31 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_switchTo", - "target": "DEFAULT_CONTENT" - }, - "position": 32 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_switchTo", - "target": "PARENT_FRAME" - }, - "position": 33 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_switchToFrame", - "node": { - "selector": "#test", - "type": "CSS" - } - }, - "position": 34 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_waitForNodeAttribute", - "waitCriterion": "IS", - "node": { - "selector": "#test", - "type": "CSS" - }, - "attribute": "test", - "value": "test", - "maxWaitTime": 10 - }, - "position": 35 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_waitForNodeAttribute", - "waitCriterion": "CONTAINS", - "node": { - "selector": "#test", - "type": "CSS" - }, - "attribute": "test", - "value": "test", - "maxWaitTime": 10 - }, - "position": 36 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_waitForNode", - "waitCriterion": "VISIBLE", - "node": { - "selector": "#test", - "type": "CSS" - }, - "maxWaitTime": 10 - }, - "position": 37 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_waitForNode", - "waitCriterion": "INVISIBLE", - "node": { - "selector": "#test", - "type": "CSS" - }, - "maxWaitTime": 10 - }, - "position": 38 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_waitForNode", - "waitCriterion": "ADDED", - "node": { - "selector": "#test", - "type": "CSS" - }, - "maxWaitTime": 10 - }, - "position": 39 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_waitForNode", - "waitCriterion": "REMOVED", - "node": { - "selector": "#test", - "type": "CSS" - }, - "maxWaitTime": 10 - }, - "position": 40 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_waitForNode", - "waitCriterion": "CLICKABLE", - "node": { - "selector": "#test", - "type": "CSS" - }, - "maxWaitTime": 10 - }, - "position": 41 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_waitForText", - "node": { - "selector": "body", - "type": "CSS" - }, - "value": "test", - "regexp": false, - "maxWaitTime": 10 - }, - "position": 42 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_waitForText", - "node": { - "selector": "body", - "type": "CSS" - }, - "value": "test", - "regexp": true, - "maxWaitTime": 10 - }, - "position": 43 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_waitForTitle", - "waitCriterion": "IS", - "value": "test", - "maxWaitTime": 10 - }, - "position": 44 - }, - { - "type": "action", - "negated": false, - "ignoreFailure": false, - "errorOutput": null, - "disabled": false, - "action": { - "type": "web_waitForTitle", - "waitCriterion": "CONTAINS", - "value": "test", - "maxWaitTime": 10 - }, - "position": 45 - } - ] -} diff --git a/backend/src/test/resources/integrationtest/ALEX-rest.project.json b/backend/src/test/resources/integrationtest/ALEX-rest.project.json deleted file mode 100644 index 112b46717..000000000 --- a/backend/src/test/resources/integrationtest/ALEX-rest.project.json +++ /dev/null @@ -1,1255 +0,0 @@ -{ - "version": "3.0.0", - "type": "project", - "project": { - "name": "ALEX", - "environments": [ - { - "name": "Production", - "urls": [ - { - "name": "Base", - "url": "http://localhost:9090/", - "default": false - }, - { - "name": "REST", - "url": "http://localhost:9090/rest", - "default": true - } - ], - "variables": [], - "default": true - } - ] - }, - "groups": [ - { - "name": "Default group", - "symbols": [ - { - "description": "", - "expectedResult": "", - "hidden": false, - "id": 223, - "inputs": [ - { - "type": "input", - "name": "jwt", - "parameterType": "STRING" - }, - { - "type": "input", - "name": "userId", - "parameterType": "STRING" - } - ], - "name": "get profile", - "outputs": [], - "steps": [ - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_call", - "method": "GET", - "url": "/users/{{$userId}}", - "baseUrl": "REST", - "timeout": 0, - "headers": { - "Authorization": "Bearer {{$jwt}}" - }, - "credentials": { - "name": "", - "password": "" - }, - "cookies": {}, - "data": null - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_checkStatus", - "status": 200 - } - } - ], - "successOutput": null, - "updatedOn": "2021-06-08T11:09:29.114+00:00" - }, - { - "description": "", - "expectedResult": "", - "hidden": false, - "id": 224, - "inputs": [ - { - "type": "input", - "name": "email", - "parameterType": "STRING" - }, - { - "type": "input", - "name": "password", - "parameterType": "STRING" - }, - { - "type": "input", - "name": "username", - "parameterType": "STRING" - } - ], - "name": "register", - "outputs": [ - { - "type": "output", - "name": "userId", - "parameterType": "STRING" - } - ], - "steps": [ - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_call", - "method": "POST", - "url": "/users", - "baseUrl": "REST", - "timeout": 0, - "headers": {}, - "credentials": { - "name": "", - "password": "" - }, - "cookies": {}, - "data": "{\n \"username\": \"{{$username}}\",\n \"email\": \"{{$email}}\",\n \"password\": \"{{$password}}\"\n}" - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_checkStatus", - "status": 201 - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_checkAttributeExists", - "attribute": "id" - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "setVariableByJSON", - "name": "userId", - "value": "id" - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_checkAttributeExists", - "attribute": "username" - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_checkAttributeExists", - "attribute": "email" - } - } - ], - "successOutput": null, - "updatedOn": "2021-06-08T11:09:29.165+00:00" - }, - { - "description": "", - "expectedResult": "", - "hidden": false, - "id": 225, - "inputs": [ - { - "type": "input", - "name": "jwt", - "parameterType": "STRING" - }, - { - "type": "input", - "name": "userId", - "parameterType": "STRING" - } - ], - "name": "demote", - "outputs": [], - "steps": [ - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_call", - "method": "PUT", - "url": "/users/{{$userId}}/demote", - "baseUrl": "REST", - "timeout": 0, - "headers": { - "Authorization": "Bearer {{$jwt}}" - }, - "credentials": { - "name": "", - "password": "" - }, - "cookies": {}, - "data": null - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_checkStatus", - "status": 200 - } - } - ], - "successOutput": null, - "updatedOn": "2021-06-08T11:09:29.190+00:00" - }, - { - "description": "", - "expectedResult": "", - "hidden": false, - "id": 226, - "inputs": [], - "name": "logout", - "outputs": [ - { - "type": "output", - "name": "jwt", - "parameterType": "STRING" - } - ], - "steps": [ - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "setVariable", - "name": "jwt", - "value": "" - } - } - ], - "successOutput": null, - "updatedOn": "2021-06-08T11:09:29.207+00:00" - }, - { - "description": "", - "expectedResult": "", - "hidden": false, - "id": 227, - "inputs": [ - { - "type": "input", - "name": "email", - "parameterType": "STRING" - }, - { - "type": "input", - "name": "password", - "parameterType": "STRING" - } - ], - "name": "auth", - "outputs": [ - { - "type": "output", - "name": "jwt", - "parameterType": "STRING" - } - ], - "steps": [ - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_call", - "method": "POST", - "url": "/users/login", - "baseUrl": "REST", - "timeout": 0, - "headers": {}, - "credentials": { - "name": "", - "password": "" - }, - "cookies": {}, - "data": "{\"email\": \"{{$email}}\", \"password\": \"{{$password}}\"}" - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": "", - "action": { - "type": "rest_checkStatus", - "status": 200 - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_checkAttributeExists", - "attribute": "token" - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "setVariableByJSON", - "name": "jwt", - "value": "token" - } - } - ], - "successOutput": null, - "updatedOn": "2021-06-08T11:09:29.222+00:00" - }, - { - "description": "", - "expectedResult": "", - "hidden": false, - "id": 228, - "inputs": [ - { - "type": "input", - "name": "jwt", - "parameterType": "STRING" - }, - { - "type": "input", - "name": "userId", - "parameterType": "STRING" - } - ], - "name": "delete profile", - "outputs": [], - "steps": [ - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_call", - "method": "DELETE", - "url": "/users/{{$userId}}", - "baseUrl": "REST", - "timeout": 0, - "headers": { - "Authorization": "Bearer {{$jwt}}" - }, - "credentials": { - "name": "", - "password": "" - }, - "cookies": {}, - "data": null - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_checkStatus", - "status": 204 - } - } - ], - "successOutput": null, - "updatedOn": "2021-06-08T11:09:29.244+00:00" - }, - { - "description": "", - "expectedResult": "", - "hidden": false, - "id": 229, - "inputs": [], - "name": "reset", - "outputs": [ - { - "type": "output", - "name": "adminId", - "parameterType": "STRING" - }, - { - "type": "output", - "name": "jwt", - "parameterType": "STRING" - } - ], - "steps": [ - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_goto", - "url": "/", - "baseUrl": "Base", - "credentials": { - "name": "", - "password": "" - } - } - }, - { - "type": "symbol", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "pSymbol": { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "email", - "parameterType": "STRING" - }, - "value": "admin@alex.example" - }, - { - "parameter": { - "type": "input", - "name": "password", - "parameterType": "STRING" - }, - "value": "admin" - } - ], - "symbol": { - "id": 227 - } - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_call", - "method": "GET", - "url": "/users/myself", - "baseUrl": "REST", - "timeout": 0, - "headers": { - "Authorization": "Bearer {{$jwt}}" - }, - "credentials": { - "name": "", - "password": "" - }, - "cookies": {}, - "data": null - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_checkStatus", - "status": 200 - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "setVariableByJSON", - "name": "adminId", - "value": "id" - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_call", - "method": "GET", - "url": "/users", - "baseUrl": "REST", - "timeout": 0, - "headers": { - "Authorization": "Bearer {{$jwt}}" - }, - "credentials": { - "name": "", - "password": "" - }, - "cookies": {}, - "data": null - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_checkStatus", - "status": 200 - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "setVariableByHttpResponse", - "name": "users" - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_executeScript", - "script": "var users = arguments[0].variables.users;\nvar adminId = arguments[0].variables.adminId;\n\nusers = JSON.parse(users).map(u => u.id).filter(id => id.toString() !== adminId);\n\nreturn users.join(',');", - "async": false, - "timeout": 10, - "name": "userIds" - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "jumpToLabel", - "label": "noUsersExist", - "script": "return arguments[0].variables.userIds === '';", - "async": false, - "timeout": 10 - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_call", - "method": "DELETE", - "url": "/users/batch/{{$userIds}}", - "baseUrl": "REST", - "timeout": 0, - "headers": { - "Authorization": "Bearer {{$jwt}}" - }, - "credentials": { - "name": "", - "password": "" - }, - "cookies": {}, - "data": null - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_checkStatus", - "status": 204 - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "createLabel", - "label": "noUsersExist" - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "setVariable", - "name": "jwt", - "value": "" - } - } - ], - "successOutput": null, - "updatedOn": "2021-06-08T11:09:29.262+00:00" - }, - { - "description": "", - "expectedResult": "", - "hidden": false, - "id": 230, - "inputs": [ - { - "type": "input", - "name": "jwt", - "parameterType": "STRING" - }, - { - "type": "input", - "name": "userId", - "parameterType": "STRING" - } - ], - "name": "promote", - "outputs": [], - "steps": [ - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_call", - "method": "PUT", - "url": "/users/{{$userId}}/promote", - "baseUrl": "REST", - "timeout": 0, - "headers": { - "Authorization": "Bearer {{$jwt}}" - }, - "credentials": { - "name": "", - "password": "" - }, - "cookies": {}, - "data": null - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_checkStatus", - "status": 200 - } - } - ], - "successOutput": null, - "updatedOn": "2021-06-08T11:09:29.278+00:00" - }, - { - "description": "", - "expectedResult": "", - "hidden": false, - "id": 231, - "inputs": [ - { - "type": "input", - "name": "jwt", - "parameterType": "STRING" - } - ], - "name": "get myself", - "outputs": [], - "steps": [ - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_call", - "method": "GET", - "url": "/users/myself", - "baseUrl": "REST", - "timeout": 0, - "headers": { - "Authorization": "Bearer {{$jwt}}" - }, - "credentials": { - "name": "", - "password": "" - }, - "cookies": {}, - "data": null - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_checkStatus", - "status": 200 - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_checkAttributeExists", - "attribute": "id" - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "rest_checkAttributeType", - "attribute": "id", - "jsonType": "INTEGER" - } - } - ], - "successOutput": null, - "updatedOn": "2021-06-08T11:09:29.296+00:00" - } - ], - "groups": [] - } - ], - "tests": [ - { - "id": 104, - "name": "test", - "preSteps": [], - "steps": [ - { - "disabled": false, - "expectedResult": "", - "expectedOutputSuccess": true, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [], - "symbol": { - "id": 229 - } - } - }, - { - "disabled": false, - "expectedResult": "", - "expectedOutputSuccess": true, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "email", - "parameterType": "STRING" - }, - "value": "user1@alex.de" - }, - { - "parameter": { - "type": "input", - "name": "password", - "parameterType": "STRING" - }, - "value": "password" - }, - { - "parameter": { - "type": "input", - "name": "username", - "parameterType": "STRING" - }, - "value": "user1" - } - ], - "symbol": { - "id": 224 - } - } - }, - { - "disabled": false, - "expectedResult": "", - "expectedOutputSuccess": true, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "email", - "parameterType": "STRING" - }, - "value": "user2@alex.de" - }, - { - "parameter": { - "type": "input", - "name": "password", - "parameterType": "STRING" - }, - "value": "password" - }, - { - "parameter": { - "type": "input", - "name": "username", - "parameterType": "STRING" - }, - "value": "user2" - } - ], - "symbol": { - "id": 224 - } - } - }, - { - "disabled": false, - "expectedResult": "", - "expectedOutputSuccess": true, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "email", - "parameterType": "STRING" - }, - "value": "user1@alex.de" - }, - { - "parameter": { - "type": "input", - "name": "password", - "parameterType": "STRING" - }, - "value": "password" - } - ], - "symbol": { - "id": 227 - } - } - }, - { - "disabled": false, - "expectedResult": "", - "expectedOutputSuccess": true, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "jwt", - "parameterType": "STRING" - }, - "value": "{{$jwt}}" - }, - { - "parameter": { - "type": "input", - "name": "userId", - "parameterType": "STRING" - }, - "value": "{{$user1Id}}" - } - ], - "symbol": { - "id": 223 - } - } - }, - { - "disabled": false, - "expectedResult": "", - "expectedOutputSuccess": false, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "jwt", - "parameterType": "STRING" - }, - "value": "{{$jwt}}" - }, - { - "parameter": { - "type": "input", - "name": "userId", - "parameterType": "STRING" - }, - "value": "{{$user2Id}}" - } - ], - "symbol": { - "id": 223 - } - } - } - ], - "postSteps": [], - "generated": false, - "status": "DONE", - "updatedOn": "2019-12-19T10:47:57.795+00:00", - "type": "case" - } - ], - "formulaSuites": [], - "learnerSetups": [ - { - "name": "LearnerSetup", - "enableCache": true, - "saved": true, - "algorithm": { - "name": "TTT" - }, - "environments": [ - { - "name": "Production", - "urls": [ - { - "name": "Base", - "url": "http://localhost:9090/", - "default": false - }, - { - "name": "REST", - "url": "http://localhost:9090/rest", - "default": true - } - ], - "variables": [], - "default": true - } - ], - "symbols": [ - { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "jwt", - "parameterType": "STRING" - }, - "value": "{{$jwt}}" - }, - { - "parameter": { - "type": "input", - "name": "userId", - "parameterType": "STRING" - }, - "value": "{{$userId}}" - } - ], - "symbol": { - "id": 223 - } - }, - { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "email", - "parameterType": "STRING" - }, - "value": "user1@alex.de" - }, - { - "parameter": { - "type": "input", - "name": "password", - "parameterType": "STRING" - }, - "value": "password" - }, - { - "parameter": { - "type": "input", - "name": "username", - "parameterType": "STRING" - }, - "value": "user1" - } - ], - "symbol": { - "id": 224 - } - }, - { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "jwt", - "parameterType": "STRING" - }, - "value": "{{$jwt}}" - }, - { - "parameter": { - "type": "input", - "name": "userId", - "parameterType": "STRING" - }, - "value": "{{$userId}}" - } - ], - "symbol": { - "id": 225 - } - }, - { - "parameterValues": [], - "symbol": { - "id": 226 - } - }, - { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "email", - "parameterType": "STRING" - }, - "value": "user1@alex.de" - }, - { - "parameter": { - "type": "input", - "name": "password", - "parameterType": "STRING" - }, - "value": "password" - } - ], - "symbol": { - "id": 227 - } - }, - { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "jwt", - "parameterType": "STRING" - }, - "value": "{{$jwt}}" - }, - { - "parameter": { - "type": "input", - "name": "userId", - "parameterType": "STRING" - }, - "value": "{{$userId}}" - } - ], - "symbol": { - "id": 228 - } - }, - { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "jwt", - "parameterType": "STRING" - }, - "value": "{{$jwt}}" - }, - { - "parameter": { - "type": "input", - "name": "userId", - "parameterType": "STRING" - }, - "value": "{{$userId}}" - } - ], - "symbol": { - "id": 230 - } - }, - { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "jwt", - "parameterType": "STRING" - }, - "value": "{{$jwt}}" - } - ], - "symbol": { - "id": 231 - } - } - ], - "preSymbol": { - "parameterValues": [], - "symbol": { - "id": 229 - } - }, - "postSymbol": null, - "equivalenceOracle": { - "type": "random_word", - "batchSize": 20, - "minLength": 10, - "maxLength": 20, - "seed": 42, - "maxNoOfTests": 50 - }, - "webDriver": { - "width": 1920, - "height": 1080, - "implicitlyWait": 0, - "pageLoadTimeout": 10, - "scriptTimeout": 10, - "platform": "ANY", - "browser": "chrome", - "version": "" - }, - "modelCheckingConfig": { - "formulaSuites": [], - "minUnfolds": 1, - "multiplier": 0.1 - } - } - ], - "testExecutionConfigs": [ - { - "name": "TestConfig", - "driverConfig": { - "width": 1920, - "height": 1080, - "implicitlyWait": 0, - "pageLoadTimeout": 10, - "scriptTimeout": 10, - "platform": "ANY", - "browser": "chrome", - "version": "" - }, - "environment": { - "name": "Production" - }, - "description": "Test", - "default": false, - "tests": [ - 104 - ] - } - ] -} diff --git a/backend/src/test/resources/integrationtest/ALEX-web.project.json b/backend/src/test/resources/integrationtest/ALEX-web.project.json deleted file mode 100644 index 825bb3f56..000000000 --- a/backend/src/test/resources/integrationtest/ALEX-web.project.json +++ /dev/null @@ -1,1033 +0,0 @@ -{ - "version": "3.0.0", - "type": "project", - "project": { - "name": "ALEX", - "environments": [ - { - "name": "Production", - "urls": [ - { - "name": "Base", - "url": "http://localhost:4200/", - "default": true - } - ], - "variables": [ - { - "name": "ADMIN_EMAIL", - "value": "admin@alex.example" - }, - { - "name": "ADMIN_PASSWORD", - "value": "admin" - } - ], - "default": true - } - ] - }, - "groups": [ - { - "name": "Default group", - "symbols": [ - { - "description": "", - "expectedResult": "", - "inputs": [], - "name": "reset", - "outputs": [], - "steps": [ - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_goto", - "url": "/", - "baseUrl": "Base", - "credentials": { - "name": "", - "password": "" - } - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_waitForNode", - "node": { - "selector": "input", - "type": "CSS" - }, - "waitCriterion": "VISIBLE", - "maxWaitTime": 10 - } - }, - { - "type": "symbol", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "pSymbol": { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "email", - "parameterType": "STRING" - }, - "value": "admin@alex.example" - }, - { - "parameter": { - "type": "input", - "name": "password", - "parameterType": "STRING" - }, - "value": "admin" - } - ], - "symbol": { - "name": "login" - } - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_clickLinkByText", - "value": "User Management", - "node": { - "selector": "#sidebar", - "type": "CSS" - } - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_waitForText", - "value": "admin@alex.example", - "regexp": false, - "node": { - "selector": "table", - "type": "CSS" - }, - "maxWaitTime": 10 - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "jumpToLabel", - "label": "L1", - "script": "return document.querySelectorAll('table tbody tr').length === 1", - "async": false, - "timeout": 10 - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_click", - "node": { - "selector": "selectable-checkbox-multiple", - "type": "CSS" - }, - "doubleClick": false - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_clickElementByText", - "node": { - "selector": "action-bar", - "type": "CSS" - }, - "tagName": "button", - "text": "Delete" - } - }, - { - "type": "symbol", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "pSymbol": { - "parameterValues": [], - "symbol": { - "name": "waitForModalOpen" - } - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_clickElementByText", - "node": { - "selector": ".modal-content", - "type": "CSS" - }, - "tagName": "button", - "text": "Yes" - } - }, - { - "type": "symbol", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "pSymbol": { - "parameterValues": [], - "symbol": { - "name": "waitForModalClose" - } - } - }, - { - "type": "symbol", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "pSymbol": { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "message", - "parameterType": "STRING" - }, - "value": "The users have been deleted" - } - ], - "symbol": { - "name": "assertToastMessage" - } - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "createLabel", - "label": "L1" - } - }, - { - "type": "symbol", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "pSymbol": { - "parameterValues": [], - "symbol": { - "name": "logout" - } - } - } - ], - "successOutput": null - }, - { - "description": "", - "expectedResult": "", - "inputs": [ - { - "type": "input", - "name": "email", - "parameterType": "STRING" - }, - { - "type": "input", - "name": "password", - "parameterType": "STRING" - } - ], - "name": "login", - "outputs": [], - "steps": [ - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_clear", - "node": { - "selector": "input[type=\"email\"]", - "type": "CSS" - } - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_clear", - "node": { - "selector": "input[type=\"password\"]", - "type": "CSS" - } - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_fill", - "node": { - "selector": "input[type=\"email\"]", - "type": "CSS" - }, - "value": "{{$email}}" - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_fill", - "node": { - "selector": "input[type=\"password\"]", - "type": "CSS" - }, - "value": "{{$password}}" - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_submit", - "node": { - "selector": "form", - "type": "CSS" - } - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_waitForNode", - "node": { - "selector": "#sidebar", - "type": "CSS" - }, - "waitCriterion": "VISIBLE", - "maxWaitTime": 10 - } - } - ], - "successOutput": null - }, - { - "description": "", - "expectedResult": "", - "inputs": [], - "name": "logout", - "outputs": [], - "steps": [ - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_click", - "node": { - "selector": "nav .nav-link", - "type": "CSS" - }, - "doubleClick": false - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_waitForNode", - "node": { - "selector": " nav .dropdown-menu", - "type": "CSS" - }, - "waitCriterion": "VISIBLE", - "maxWaitTime": 10 - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_clickElementByText", - "node": { - "selector": " nav .dropdown-menu", - "type": "CSS" - }, - "tagName": "a", - "text": "Logout" - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_waitForNode", - "node": { - "selector": "input[type=\"password\"]", - "type": "CSS" - }, - "waitCriterion": "VISIBLE", - "maxWaitTime": 10 - } - } - ], - "successOutput": null - }, - { - "description": "", - "expectedResult": "", - "inputs": [ - { - "type": "input", - "name": "email", - "parameterType": "STRING" - }, - { - "type": "input", - "name": "password", - "parameterType": "STRING" - } - ], - "name": "register", - "outputs": [], - "steps": [ - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_clear", - "node": { - "selector": "input[type=\"email\"]", - "type": "CSS" - } - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_clear", - "node": { - "selector": "input[type=\"password\"]", - "type": "CSS" - } - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_fill", - "node": { - "selector": "input[type=\"email\"]", - "type": "CSS" - }, - "value": "{{$email}}" - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_fill", - "node": { - "selector": "input[type=\"password\"]", - "type": "CSS" - }, - "value": "{{$password}}" - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_clickElementByText", - "node": { - "selector": "body", - "type": "CSS" - }, - "tagName": "button", - "text": "Sign up" - } - } - ], - "successOutput": null - } - ], - "groups": [] - }, - { - "name": "Utils", - "symbols": [ - { - "description": "", - "expectedResult": "", - "inputs": [ - { - "type": "input", - "name": "message", - "parameterType": "STRING" - } - ], - "name": "assertToastMessage", - "outputs": [], - "steps": [ - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_waitForNode", - "node": { - "selector": "#toast-container .toast-message", - "type": "CSS" - }, - "waitCriterion": "CLICKABLE", - "maxWaitTime": 10 - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_checkForText", - "value": "{{$message}}", - "regexp": false, - "node": { - "selector": "#toast-container .toast-message", - "type": "CSS" - } - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_click", - "node": { - "selector": "#toast-container .toast-message", - "type": "CSS" - }, - "doubleClick": false - } - }, - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_waitForNode", - "node": { - "selector": "#toast-container .toast-message", - "type": "CSS" - }, - "waitCriterion": "REMOVED", - "maxWaitTime": 10 - } - } - ], - "successOutput": null - }, - { - "description": "", - "expectedResult": "", - "inputs": [], - "name": "waitForModalOpen", - "outputs": [], - "steps": [ - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_waitForNode", - "node": { - "selector": ".modal-content", - "type": "CSS" - }, - "waitCriterion": "VISIBLE", - "maxWaitTime": 10 - } - } - ], - "successOutput": null - }, - { - "description": "", - "expectedResult": "", - "inputs": [], - "name": "waitForModalClose", - "outputs": [], - "steps": [ - { - "type": "action", - "disabled": false, - "ignoreFailure": false, - "negated": false, - "errorOutput": null, - "action": { - "type": "web_waitForNode", - "node": { - "selector": ".modal-content", - "type": "CSS" - }, - "waitCriterion": "REMOVED", - "maxWaitTime": 10 - } - } - ], - "successOutput": null - } - ], - "groups": [] - } - ], - "tests": [ - { - "name": "Authentication", - "tests": [ - { - "type": "case", - "name": "test login logout", - "preSteps": [ - { - "expectedResult": "", - "expectedOutputSuccess": true, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [], - "symbol": { - "name": "reset" - } - } - } - ], - "steps": [ - { - "expectedResult": "", - "expectedOutputSuccess": true, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "email", - "parameterType": "STRING" - }, - "value": "test@test.de" - }, - { - "parameter": { - "type": "input", - "name": "password", - "parameterType": "STRING" - }, - "value": "test" - } - ], - "symbol": { - "name": "register" - } - } - }, - { - "expectedResult": "", - "expectedOutputSuccess": true, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "message", - "parameterType": "STRING" - }, - "value": "Registration successful" - } - ], - "symbol": { - "name": "assertToastMessage" - } - } - }, - { - "expectedResult": "", - "expectedOutputSuccess": true, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "email", - "parameterType": "STRING" - }, - "value": "test@test.de" - }, - { - "parameter": { - "type": "input", - "name": "password", - "parameterType": "STRING" - }, - "value": "test" - } - ], - "symbol": { - "name": "login" - } - } - }, - { - "expectedResult": "", - "expectedOutputSuccess": true, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "message", - "parameterType": "STRING" - }, - "value": "You have logged in" - } - ], - "symbol": { - "name": "assertToastMessage" - } - } - }, - { - "expectedResult": "", - "expectedOutputSuccess": true, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [], - "symbol": { - "name": "logout" - } - } - } - ], - "postSteps": [], - "generated": false, - "status": "DONE" - }, - { - "type": "case", - "name": "test register", - "preSteps": [ - { - "expectedResult": "", - "expectedOutputSuccess": true, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [], - "symbol": { - "name": "reset" - } - } - } - ], - "steps": [ - { - "expectedResult": "", - "expectedOutputSuccess": true, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "email", - "parameterType": "STRING" - }, - "value": "test@test.de" - }, - { - "parameter": { - "type": "input", - "name": "password", - "parameterType": "STRING" - }, - "value": "test" - } - ], - "symbol": { - "name": "register" - } - } - }, - { - "expectedResult": "", - "expectedOutputSuccess": true, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "message", - "parameterType": "STRING" - }, - "value": "Registration successful" - } - ], - "symbol": { - "name": "assertToastMessage" - } - } - }, - { - "expectedResult": "", - "expectedOutputSuccess": true, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "email", - "parameterType": "STRING" - }, - "value": "test@test.de" - }, - { - "parameter": { - "type": "input", - "name": "password", - "parameterType": "STRING" - }, - "value": "test" - } - ], - "symbol": { - "name": "login" - } - } - }, - { - "expectedResult": "", - "expectedOutputSuccess": true, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [], - "symbol": { - "name": "logout" - } - } - } - ], - "postSteps": [], - "generated": false, - "status": "DONE" - }, - { - "type": "case", - "name": "test do not register twice", - "preSteps": [ - { - "expectedResult": "", - "expectedOutputSuccess": true, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [], - "symbol": { - "name": "reset" - } - } - } - ], - "steps": [ - { - "expectedResult": "", - "expectedOutputSuccess": true, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "email", - "parameterType": "STRING" - }, - "value": "test@test.de" - }, - { - "parameter": { - "type": "input", - "name": "password", - "parameterType": "STRING" - }, - "value": "test" - } - ], - "symbol": { - "name": "register" - } - } - }, - { - "expectedResult": "", - "expectedOutputSuccess": true, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "email", - "parameterType": "STRING" - }, - "value": "test@test.de" - }, - { - "parameter": { - "type": "input", - "name": "password", - "parameterType": "STRING" - }, - "value": "test" - } - ], - "symbol": { - "name": "register" - } - } - }, - { - "expectedResult": "", - "expectedOutputSuccess": true, - "expectedOutputMessage": "", - "pSymbol": { - "parameterValues": [ - { - "parameter": { - "type": "input", - "name": "message", - "parameterType": "STRING" - }, - "value": "Registration failed" - } - ], - "symbol": { - "name": "assertToastMessage" - } - } - } - ], - "postSteps": [], - "generated": false, - "status": "DONE" - } - ], - "type": "suite" - } - ] -} diff --git a/book/404.html b/book/404.html new file mode 100644 index 000000000..7c6fdd424 --- /dev/null +++ b/book/404.html @@ -0,0 +1,20 @@ + + + + + + ALEX Docs (v3.0.0) + + + + + + + + +

404

There's nothing here.
+ Take me home. +
+ + + diff --git a/book/assets/css/0.styles.99052a59.css b/book/assets/css/0.styles.99052a59.css new file mode 100644 index 000000000..8661e3e26 --- /dev/null +++ b/book/assets/css/0.styles.99052a59.css @@ -0,0 +1 @@ +code[class*=language-],pre[class*=language-]{color:#ccc;background:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#999}.token.punctuation{color:#ccc}.token.attr-name,.token.deleted,.token.namespace,.token.tag{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.function,.token.number{color:#f08d49}.token.class-name,.token.constant,.token.property,.token.symbol{color:#f8c555}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#cc99cd}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#7ec699}.token.entity,.token.operator,.token.url{color:#67cdcc}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}.theme-default-content code{color:#476582;padding:.25rem .5rem;margin:0;font-size:.85em;background-color:rgba(27,31,35,.05);border-radius:3px}.theme-default-content code .token.deleted{color:#ec5975}.theme-default-content code .token.inserted{color:#3eaf7c}.theme-default-content pre,.theme-default-content pre[class*=language-]{line-height:1.4;padding:1.25rem 1.5rem;margin:.85rem 0;background-color:#282c34;border-radius:6px;overflow:auto}.theme-default-content pre[class*=language-] code,.theme-default-content pre code{color:#fff;padding:0;background-color:transparent;border-radius:0}div[class*=language-]{position:relative;background-color:#282c34;border-radius:6px}div[class*=language-] .highlight-lines{-webkit-user-select:none;user-select:none;padding-top:1.3rem;position:absolute;top:0;left:0;width:100%;line-height:1.4}div[class*=language-] .highlight-lines .highlighted{background-color:rgba(0,0,0,.66)}div[class*=language-] pre,div[class*=language-] pre[class*=language-]{background:transparent;position:relative;z-index:1}div[class*=language-]:before{position:absolute;z-index:3;top:.8em;right:1em;font-size:.75rem;color:hsla(0,0%,100%,.4)}div[class*=language-]:not(.line-numbers-mode) .line-numbers-wrapper{display:none}div[class*=language-].line-numbers-mode .highlight-lines .highlighted{position:relative}div[class*=language-].line-numbers-mode .highlight-lines .highlighted:before{content:" ";position:absolute;z-index:3;left:0;top:0;display:block;width:3.5rem;height:100%;background-color:rgba(0,0,0,.66)}div[class*=language-].line-numbers-mode pre{padding-left:4.5rem;vertical-align:middle}div[class*=language-].line-numbers-mode .line-numbers-wrapper{position:absolute;top:0;width:3.5rem;text-align:center;color:hsla(0,0%,100%,.3);padding:1.25rem 0;line-height:1.4}div[class*=language-].line-numbers-mode .line-numbers-wrapper br{-webkit-user-select:none;user-select:none}div[class*=language-].line-numbers-mode .line-numbers-wrapper .line-number{position:relative;z-index:4;-webkit-user-select:none;user-select:none;font-size:.85em}div[class*=language-].line-numbers-mode:after{content:"";position:absolute;z-index:2;top:0;left:0;width:3.5rem;height:100%;border-radius:6px 0 0 6px;border-right:1px solid rgba(0,0,0,.66);background-color:#282c34}div[class~=language-js]:before{content:"js"}div[class~=language-ts]:before{content:"ts"}div[class~=language-html]:before{content:"html"}div[class~=language-md]:before{content:"md"}div[class~=language-vue]:before{content:"vue"}div[class~=language-css]:before{content:"css"}div[class~=language-sass]:before{content:"sass"}div[class~=language-scss]:before{content:"scss"}div[class~=language-less]:before{content:"less"}div[class~=language-stylus]:before{content:"stylus"}div[class~=language-go]:before{content:"go"}div[class~=language-java]:before{content:"java"}div[class~=language-c]:before{content:"c"}div[class~=language-sh]:before{content:"sh"}div[class~=language-yaml]:before{content:"yaml"}div[class~=language-py]:before{content:"py"}div[class~=language-docker]:before{content:"docker"}div[class~=language-dockerfile]:before{content:"dockerfile"}div[class~=language-makefile]:before{content:"makefile"}div[class~=language-javascript]:before{content:"js"}div[class~=language-typescript]:before{content:"ts"}div[class~=language-markup]:before{content:"html"}div[class~=language-markdown]:before{content:"md"}div[class~=language-json]:before{content:"json"}div[class~=language-ruby]:before{content:"rb"}div[class~=language-python]:before{content:"py"}div[class~=language-bash]:before{content:"sh"}div[class~=language-php]:before{content:"php"}.custom-block .custom-block-title{font-weight:600;margin-bottom:-.4rem}.custom-block.danger,.custom-block.tip,.custom-block.warning{padding:.1rem 1.5rem;border-left-width:.5rem;border-left-style:solid;margin:1rem 0}.custom-block.tip{background-color:#f3f5f7;border-color:#42b983}.custom-block.warning{background-color:rgba(255,229,100,.3);border-color:#e7c000;color:#6b5900}.custom-block.warning .custom-block-title{color:#b29400}.custom-block.warning a{color:#2c3e50}.custom-block.danger{background-color:#ffe6e6;border-color:#c00;color:#4d0000}.custom-block.danger .custom-block-title{color:#900}.custom-block.danger a{color:#2c3e50}.custom-block.details{display:block;position:relative;border-radius:2px;margin:1.6em 0;padding:1.6em;background-color:#eee}.custom-block.details h4{margin-top:0}.custom-block.details figure:last-child,.custom-block.details p:last-child{margin-bottom:0;padding-bottom:0}.custom-block.details summary{outline:none;cursor:pointer}.arrow{display:inline-block;width:0;height:0}.arrow.up{border-bottom:6px solid #ccc}.arrow.down,.arrow.up{border-left:4px solid transparent;border-right:4px solid transparent}.arrow.down{border-top:6px solid #ccc}.arrow.right{border-left:6px solid #ccc}.arrow.left,.arrow.right{border-top:4px solid transparent;border-bottom:4px solid transparent}.arrow.left{border-right:6px solid #ccc}.theme-default-content:not(.custom){max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.theme-default-content:not(.custom){padding:2rem}}@media (max-width:419px){.theme-default-content:not(.custom){padding:1.5rem}}.table-of-contents .badge{vertical-align:middle}body,html{padding:0;margin:0;background-color:#fff}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:16px;color:#2c3e50}.page{padding-left:20rem}.navbar{z-index:20;right:0;height:3.6rem;background-color:#fff;box-sizing:border-box;border-bottom:1px solid #eaecef}.navbar,.sidebar-mask{position:fixed;top:0;left:0}.sidebar-mask{z-index:9;width:100vw;height:100vh;display:none}.sidebar{font-size:16px;background-color:#fff;width:20rem;position:fixed;z-index:10;margin:0;top:3.6rem;left:0;bottom:0;box-sizing:border-box;border-right:1px solid #eaecef;overflow-y:auto}.theme-default-content:not(.custom)>:first-child{margin-top:3.6rem}.theme-default-content:not(.custom) a:hover{text-decoration:underline}.theme-default-content:not(.custom) p.demo{padding:1rem 1.5rem;border:1px solid #ddd;border-radius:4px}.theme-default-content:not(.custom) img{max-width:100%}.theme-default-content.custom{padding:0;margin:0}.theme-default-content.custom img{max-width:100%}a{font-weight:500;text-decoration:none}a,p a code{color:#3eaf7c}p a code{font-weight:400}kbd{background:#eee;border:.15rem solid #ddd;border-bottom:.25rem solid #ddd;border-radius:.15rem;padding:0 .15em}blockquote{font-size:1rem;color:#999;border-left:.2rem solid #dfe2e5;margin:1rem 0;padding:.25rem 0 .25rem 1rem}blockquote>p{margin:0}ol,ul{padding-left:1.2em}strong{font-weight:600}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.25}.theme-default-content:not(.custom)>h1,.theme-default-content:not(.custom)>h2,.theme-default-content:not(.custom)>h3,.theme-default-content:not(.custom)>h4,.theme-default-content:not(.custom)>h5,.theme-default-content:not(.custom)>h6{margin-top:-3.1rem;padding-top:4.6rem;margin-bottom:0}.theme-default-content:not(.custom)>h1:first-child,.theme-default-content:not(.custom)>h2:first-child,.theme-default-content:not(.custom)>h3:first-child,.theme-default-content:not(.custom)>h4:first-child,.theme-default-content:not(.custom)>h5:first-child,.theme-default-content:not(.custom)>h6:first-child{margin-top:-1.5rem;margin-bottom:1rem}.theme-default-content:not(.custom)>h1:first-child+.custom-block,.theme-default-content:not(.custom)>h1:first-child+p,.theme-default-content:not(.custom)>h1:first-child+pre,.theme-default-content:not(.custom)>h2:first-child+.custom-block,.theme-default-content:not(.custom)>h2:first-child+p,.theme-default-content:not(.custom)>h2:first-child+pre,.theme-default-content:not(.custom)>h3:first-child+.custom-block,.theme-default-content:not(.custom)>h3:first-child+p,.theme-default-content:not(.custom)>h3:first-child+pre,.theme-default-content:not(.custom)>h4:first-child+.custom-block,.theme-default-content:not(.custom)>h4:first-child+p,.theme-default-content:not(.custom)>h4:first-child+pre,.theme-default-content:not(.custom)>h5:first-child+.custom-block,.theme-default-content:not(.custom)>h5:first-child+p,.theme-default-content:not(.custom)>h5:first-child+pre,.theme-default-content:not(.custom)>h6:first-child+.custom-block,.theme-default-content:not(.custom)>h6:first-child+p,.theme-default-content:not(.custom)>h6:first-child+pre{margin-top:2rem}h1:focus .header-anchor,h1:hover .header-anchor,h2:focus .header-anchor,h2:hover .header-anchor,h3:focus .header-anchor,h3:hover .header-anchor,h4:focus .header-anchor,h4:hover .header-anchor,h5:focus .header-anchor,h5:hover .header-anchor,h6:focus .header-anchor,h6:hover .header-anchor{opacity:1}h1{font-size:2.2rem}h2{font-size:1.65rem;padding-bottom:.3rem;border-bottom:1px solid #eaecef}h3{font-size:1.35rem}a.header-anchor{font-size:.85em;float:left;margin-left:-.87em;padding-right:.23em;margin-top:.125em;opacity:0}a.header-anchor:focus,a.header-anchor:hover{text-decoration:none}.line-number,code,kbd{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}ol,p,ul{line-height:1.7}hr{border:0;border-top:1px solid #eaecef}table{border-collapse:collapse;margin:1rem 0;display:block;overflow-x:auto}tr{border-top:1px solid #dfe2e5}tr:nth-child(2n){background-color:#f6f8fa}td,th{border:1px solid #dfe2e5;padding:.6em 1em}.theme-container.sidebar-open .sidebar-mask{display:block}.theme-container.no-navbar .theme-default-content:not(.custom)>h1,.theme-container.no-navbar h2,.theme-container.no-navbar h3,.theme-container.no-navbar h4,.theme-container.no-navbar h5,.theme-container.no-navbar h6{margin-top:1.5rem;padding-top:0}.theme-container.no-navbar .sidebar{top:0}@media (min-width:720px){.theme-container.no-sidebar .sidebar{display:none}.theme-container.no-sidebar .page{padding-left:0}}@media (max-width:959px){.sidebar{font-size:15px;width:16.4rem}.page{padding-left:16.4rem}}@media (max-width:719px){.sidebar{top:0;padding-top:3.6rem;transform:translateX(-100%);transition:transform .2s ease}.page{padding-left:0}.theme-container.sidebar-open .sidebar{transform:translateX(0)}.theme-container.no-navbar .sidebar{padding-top:0}}@media (max-width:419px){h1{font-size:1.9rem}.theme-default-content div[class*=language-]{margin:.85rem -1.5rem;border-radius:0}}#nprogress{pointer-events:none}#nprogress .bar{background:#3eaf7c;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #3eaf7c,0 0 5px #3eaf7c;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border-color:#3eaf7c transparent transparent #3eaf7c;border-style:solid;border-width:2px;border-radius:50%;-webkit-animation:nprogress-spinner .4s linear infinite;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@-webkit-keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.icon.outbound{color:#aaa;display:inline-block;vertical-align:middle;position:relative;top:-1px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.home{padding:3.6rem 2rem 0;max-width:960px;margin:0 auto;display:block}.home .hero{text-align:center}.home .hero img{max-width:100%;max-height:280px;display:block;margin:3rem auto 1.5rem}.home .hero h1{font-size:3rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.8rem auto}.home .hero .description{max-width:35rem;font-size:1.6rem;line-height:1.3;color:#6a8bad}.home .hero .action-button{display:inline-block;font-size:1.2rem;color:#fff;background-color:#3eaf7c;padding:.8rem 1.6rem;border-radius:4px;transition:background-color .1s ease;box-sizing:border-box;border-bottom:1px solid #389d70}.home .hero .action-button:hover{background-color:#4abf8a}.home .features{border-top:1px solid #eaecef;padding:1.2rem 0;margin-top:2.5rem;display:flex;flex-wrap:wrap;align-items:flex-start;align-content:stretch;justify-content:space-between}.home .feature{flex-grow:1;flex-basis:30%;max-width:30%}.home .feature h2{font-size:1.4rem;font-weight:500;border-bottom:none;padding-bottom:0;color:#3a5169}.home .feature p{color:#4e6e8e}.home .footer{padding:2.5rem;border-top:1px solid #eaecef;text-align:center;color:#4e6e8e}@media (max-width:719px){.home .features{flex-direction:column}.home .feature{max-width:100%;padding:0 2.5rem}}@media (max-width:419px){.home{padding-left:1.5rem;padding-right:1.5rem}.home .hero img{max-height:210px;margin:2rem auto 1.2rem}.home .hero h1{font-size:2rem}.home .hero .action,.home .hero .description,.home .hero h1{margin:1.2rem auto}.home .hero .description{font-size:1.2rem}.home .hero .action-button{font-size:1rem;padding:.6rem 1.2rem}.home .feature h2{font-size:1.25rem}}.search-box{display:inline-block;position:relative;margin-right:1rem}.search-box input{cursor:text;width:10rem;height:2rem;color:#4e6e8e;display:inline-block;border:1px solid #cfd4db;border-radius:2rem;font-size:.9rem;line-height:2rem;padding:0 .5rem 0 2rem;outline:none;transition:all .2s ease;background:#fff url(http://github.com/alex/book/assets/img/search.83621669.svg) .6rem .5rem no-repeat;background-size:1rem}.search-box input:focus{cursor:auto;border-color:#3eaf7c}.search-box .suggestions{background:#fff;width:20rem;position:absolute;top:2rem;border:1px solid #cfd4db;border-radius:6px;padding:.4rem;list-style-type:none}.search-box .suggestions.align-right{right:0}.search-box .suggestion{line-height:1.4;padding:.4rem .6rem;border-radius:4px;cursor:pointer}.search-box .suggestion a{white-space:normal;color:#5d82a6}.search-box .suggestion a .page-title{font-weight:600}.search-box .suggestion a .header{font-size:.9em;margin-left:.25em}.search-box .suggestion.focused{background-color:#f3f4f5}.search-box .suggestion.focused a{color:#3eaf7c}@media (max-width:959px){.search-box input{cursor:pointer;width:0;border-color:transparent;position:relative}.search-box input:focus{cursor:text;left:0;width:10rem}}@media (-ms-high-contrast:none){.search-box input{height:2rem}}@media (max-width:959px) and (min-width:719px){.search-box .suggestions{left:0}}@media (max-width:719px){.search-box{margin-right:0}.search-box input{left:1rem}.search-box .suggestions{right:0}}@media (max-width:419px){.search-box .suggestions{width:calc(100vw - 4rem)}.search-box input:focus{width:8rem}}.sidebar-button{cursor:pointer;display:none;width:1.25rem;height:1.25rem;position:absolute;padding:.6rem;top:.6rem;left:1rem}.sidebar-button .icon{display:block;width:1.25rem;height:1.25rem}@media (max-width:719px){.sidebar-button{display:block}}.dropdown-enter,.dropdown-leave-to{height:0!important}.dropdown-wrapper{cursor:pointer}.dropdown-wrapper .dropdown-title,.dropdown-wrapper .mobile-dropdown-title{display:block;font-size:.9rem;font-family:inherit;cursor:inherit;padding:inherit;line-height:1.4rem;background:transparent;border:none;font-weight:500;color:#2c3e50}.dropdown-wrapper .dropdown-title:hover,.dropdown-wrapper .mobile-dropdown-title:hover{border-color:transparent}.dropdown-wrapper .dropdown-title .arrow,.dropdown-wrapper .mobile-dropdown-title .arrow{vertical-align:middle;margin-top:-1px;margin-left:.4rem}.dropdown-wrapper .mobile-dropdown-title{display:none;font-weight:600}.dropdown-wrapper .mobile-dropdown-title font-size inherit:hover{color:#3eaf7c}.dropdown-wrapper .nav-dropdown .dropdown-item{color:inherit;line-height:1.7rem}.dropdown-wrapper .nav-dropdown .dropdown-item h4{margin:.45rem 0 0;border-top:1px solid #eee;padding:1rem 1.5rem .45rem 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper{padding:0;list-style:none}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper .dropdown-subitem{font-size:.9em}.dropdown-wrapper .nav-dropdown .dropdown-item a{display:block;line-height:1.7rem;position:relative;border-bottom:none;font-weight:400;margin-bottom:0;padding:0 1.5rem 0 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active,.dropdown-wrapper .nav-dropdown .dropdown-item a:hover{color:#3eaf7c}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{content:"";width:0;height:0;border-left:5px solid #3eaf7c;border-top:3px solid transparent;border-bottom:3px solid transparent;position:absolute;top:calc(50% - 2px);left:9px}.dropdown-wrapper .nav-dropdown .dropdown-item:first-child h4{margin-top:0;padding-top:0;border-top:0}@media (max-width:719px){.dropdown-wrapper.open .dropdown-title{margin-bottom:.5rem}.dropdown-wrapper .dropdown-title{display:none}.dropdown-wrapper .mobile-dropdown-title{display:block}.dropdown-wrapper .nav-dropdown{transition:height .1s ease-out;overflow:hidden}.dropdown-wrapper .nav-dropdown .dropdown-item h4{border-top:0;margin-top:0;padding-top:0}.dropdown-wrapper .nav-dropdown .dropdown-item>a,.dropdown-wrapper .nav-dropdown .dropdown-item h4{font-size:15px;line-height:2rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem{font-size:14px;padding-left:1rem}}@media (min-width:719px){.dropdown-wrapper{height:1.8rem}.dropdown-wrapper.open .nav-dropdown,.dropdown-wrapper:hover .nav-dropdown{display:block!important}.dropdown-wrapper.open:blur{display:none}.dropdown-wrapper .nav-dropdown{display:none;height:auto!important;box-sizing:border-box;max-height:calc(100vh - 2.7rem);overflow-y:auto;position:absolute;top:100%;right:0;background-color:#fff;padding:.6rem 0;border:1px solid;border-color:#ddd #ddd #ccc;text-align:left;border-radius:.25rem;white-space:nowrap;margin:0}}.nav-links{display:inline-block}.nav-links a{line-height:1.4rem;color:inherit}.nav-links a.router-link-active,.nav-links a:hover{color:#3eaf7c}.nav-links .nav-item{position:relative;display:inline-block;margin-left:1.5rem;line-height:2rem}.nav-links .nav-item:first-child{margin-left:0}.nav-links .repo-link{margin-left:1.5rem}@media (max-width:719px){.nav-links .nav-item,.nav-links .repo-link{margin-left:0}}@media (min-width:719px){.nav-links a.router-link-active,.nav-links a:hover{color:#2c3e50}.nav-item>a:not(.external).router-link-active,.nav-item>a:not(.external):hover{margin-bottom:-2px;border-bottom:2px solid #46bd87}}.navbar{padding:.7rem 1.5rem;line-height:2.2rem}.navbar a,.navbar img,.navbar span{display:inline-block}.navbar .logo{height:2.2rem;min-width:2.2rem;margin-right:.8rem;vertical-align:top}.navbar .site-name{font-size:1.3rem;font-weight:600;color:#2c3e50;position:relative}.navbar .links{padding-left:1.5rem;box-sizing:border-box;background-color:#fff;white-space:nowrap;font-size:.9rem;position:absolute;right:1.5rem;top:.7rem;display:flex}.navbar .links .search-box{flex:0 0 auto;vertical-align:top}@media (max-width:719px){.navbar{padding-left:4rem}.navbar .can-hide{display:none}.navbar .links{padding-left:1.5rem}.navbar .site-name{width:calc(100vw - 9.4rem);overflow:hidden;white-space:nowrap;text-overflow:ellipsis}}.page-edit{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-edit{padding:2rem}}@media (max-width:419px){.page-edit{padding:1.5rem}}.page-edit{padding-top:1rem;padding-bottom:1rem;overflow:auto}.page-edit .edit-link{display:inline-block}.page-edit .edit-link a{color:#4e6e8e;margin-right:.25rem}.page-edit .last-updated{float:right;font-size:.9em}.page-edit .last-updated .prefix{font-weight:500;color:#4e6e8e}.page-edit .last-updated .time{font-weight:400;color:#767676}@media (max-width:719px){.page-edit .edit-link{margin-bottom:.5rem}.page-edit .last-updated{font-size:.8em;float:none;text-align:left}}.page-nav{max-width:740px;margin:0 auto;padding:2rem 2.5rem}@media (max-width:959px){.page-nav{padding:2rem}}@media (max-width:419px){.page-nav{padding:1.5rem}}.page-nav{padding-top:1rem;padding-bottom:0}.page-nav .inner{min-height:2rem;margin-top:0;border-top:1px solid #eaecef;padding-top:1rem;overflow:auto}.page-nav .next{float:right}.page{padding-bottom:2rem;display:block}.sidebar-group .sidebar-group{padding-left:.5em}.sidebar-group:not(.collapsable) .sidebar-heading:not(.clickable){cursor:auto;color:inherit}.sidebar-group.is-sub-group{padding-left:0}.sidebar-group.is-sub-group>.sidebar-heading{font-size:.95em;line-height:1.4;font-weight:400;padding-left:2rem}.sidebar-group.is-sub-group>.sidebar-heading:not(.clickable){opacity:.5}.sidebar-group.is-sub-group>.sidebar-group-items{padding-left:1rem}.sidebar-group.is-sub-group>.sidebar-group-items>li>.sidebar-link{font-size:.95em;border-left:none}.sidebar-group.depth-2>.sidebar-heading{border-left:none}.sidebar-heading{color:#2c3e50;transition:color .15s ease;cursor:pointer;font-size:1.1em;font-weight:700;padding:.35rem 1.5rem .35rem 1.25rem;width:100%;box-sizing:border-box;margin:0;border-left:.25rem solid transparent}.sidebar-heading.open,.sidebar-heading:hover{color:inherit}.sidebar-heading .arrow{position:relative;top:-.12em;left:.5em}.sidebar-heading.clickable.active{font-weight:600;color:#3eaf7c;border-left-color:#3eaf7c}.sidebar-heading.clickable:hover{color:#3eaf7c}.sidebar-group-items{transition:height .1s ease-out;font-size:.95em;overflow:hidden}.sidebar .sidebar-sub-headers{padding-left:1rem;font-size:.95em}a.sidebar-link{font-size:1em;font-weight:400;display:inline-block;color:#2c3e50;border-left:.25rem solid transparent;padding:.35rem 1rem .35rem 1.25rem;line-height:1.4;width:100%;box-sizing:border-box}a.sidebar-link:hover{color:#3eaf7c}a.sidebar-link.active{font-weight:600;color:#3eaf7c;border-left-color:#3eaf7c}.sidebar-group a.sidebar-link{padding-left:2rem}.sidebar-sub-headers a.sidebar-link{padding-top:.25rem;padding-bottom:.25rem;border-left:none}.sidebar-sub-headers a.sidebar-link.active{font-weight:500}a,a.sidebar-link:hover,a:hover{color:#87b82b}a.sidebar-link.active{color:#87b82b;border-left-color:#87b82b}figure{display:flex;margin:0;padding:0;background:#eef0f3}figure.bordered{border:1px solid #cecece}figure img{display:block;margin:auto}.label{display:inline-block;background:red;width:1rem;border-radius:1rem;height:1rem;line-height:1rem;font-size:.75rem;font-weight:700;color:#fff;padding-left:4px;box-sizing:border-box}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem;line-height:1.7}.alert.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.definition{line-height:1.7}table{display:table;table-layout:auto;width:100%}.sidebar ul{padding:0;margin:0;list-style-type:none}.sidebar a{display:inline-block}.sidebar .nav-links{display:none;border-bottom:1px solid #eaecef;padding:.5rem 0 .75rem}.sidebar .nav-links a{font-weight:600}.sidebar .nav-links .nav-item,.sidebar .nav-links .repo-link{display:block;line-height:1.25rem;font-size:1.1em;padding:.5rem 0 .5rem 1.5rem}.sidebar>.sidebar-links{padding:1.5rem 0}.sidebar>.sidebar-links>li>a.sidebar-link{font-size:1.1em;line-height:1.7;font-weight:700}.sidebar>.sidebar-links>li:not(:first-child){margin-top:.75rem}@media (max-width:719px){.sidebar .nav-links{display:block}.sidebar .nav-links .dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{top:calc(1rem - 2px)}.sidebar>.sidebar-links{padding:1rem 0}}a.sidebar-link[data-v-506a1a1b]:hover,a[data-v-506a1a1b],a[data-v-506a1a1b]:hover{color:#87b82b}a.sidebar-link.active[data-v-506a1a1b]{color:#87b82b;border-left-color:#87b82b}figure[data-v-506a1a1b]{display:flex;margin:0;padding:0;background:#eef0f3}figure.bordered[data-v-506a1a1b]{border:1px solid #cecece}figure img[data-v-506a1a1b]{display:block;margin:auto}.label[data-v-506a1a1b]{display:inline-block;background:red;width:1rem;border-radius:1rem;height:1rem;line-height:1rem;font-size:.75rem;font-weight:700;color:#fff;padding-left:4px;box-sizing:border-box}.alert[data-v-506a1a1b]{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem;line-height:1.7}.alert.alert-info[data-v-506a1a1b]{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.definition[data-v-506a1a1b]{line-height:1.7}table[data-v-506a1a1b]{display:table;table-layout:auto;width:100%}.definition[data-v-506a1a1b]{padding-left:1.5em;text-indent:-1.5em;margin-bottom:1rem}.definition .term[data-v-506a1a1b]{font-weight:500;margin-right:.25rem}a.sidebar-link[data-v-20a7c7b2]:hover,a[data-v-20a7c7b2],a[data-v-20a7c7b2]:hover{color:#87b82b}a.sidebar-link.active[data-v-20a7c7b2]{color:#87b82b;border-left-color:#87b82b}figure[data-v-20a7c7b2]{display:flex;margin:0;padding:0;background:#eef0f3}figure.bordered[data-v-20a7c7b2]{border:1px solid #cecece}figure img[data-v-20a7c7b2]{display:block;margin:auto}.label[data-v-20a7c7b2]{display:inline-block;background:red;width:1rem;border-radius:1rem;height:1rem;line-height:1rem;font-size:.75rem;font-weight:700;color:#fff;padding-left:4px;box-sizing:border-box}.alert[data-v-20a7c7b2]{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem;line-height:1.7}.alert.alert-info[data-v-20a7c7b2]{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.definition[data-v-20a7c7b2]{line-height:1.7}table[data-v-20a7c7b2]{display:table;table-layout:auto;width:100%}.slide[data-v-20a7c7b2]{display:none}a.sidebar-link[data-v-516b99a7]:hover,a[data-v-516b99a7],a[data-v-516b99a7]:hover{color:#87b82b}a.sidebar-link.active[data-v-516b99a7]{color:#87b82b;border-left-color:#87b82b}figure[data-v-516b99a7]{display:flex;margin:0;padding:0;background:#eef0f3}figure.bordered[data-v-516b99a7]{border:1px solid #cecece}figure img[data-v-516b99a7]{display:block;margin:auto}.label[data-v-516b99a7]{display:inline-block;background:red;width:1rem;border-radius:1rem;height:1rem;line-height:1rem;font-size:.75rem;font-weight:700;color:#fff;padding-left:4px;box-sizing:border-box}.alert[data-v-516b99a7]{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem;line-height:1.7}.alert.alert-info[data-v-516b99a7]{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.definition[data-v-516b99a7]{line-height:1.7}table[data-v-516b99a7]{display:table;table-layout:auto;width:100%}.slides[data-v-516b99a7]{background:#fff;border:1px solid #dedede;box-shadow:0 1px 2px rgba(0,0,0,.05);margin:1rem 0}.slides .slide-image img[data-v-516b99a7]{display:block;max-width:100%;margin:auto}.slides .slide-content[data-v-516b99a7]{padding:1rem;border-top:1px solid #dedede;border-bottom:1px solid #dedede}.slides .slide-content .slide-title[data-v-516b99a7]{margin:0 0 .5rem}.slides .slide-navigation[data-v-516b99a7]{display:flex;align-items:baseline;padding:0 .5rem;background:#fbfbfb}.slides .slide-navigation .indicator[data-v-516b99a7]{width:100%;margin-left:.5rem;color:#8a8a8a}.slides .slide-navigation .buttons[data-v-516b99a7]{flex-shrink:0}.slides .slide-navigation button[data-v-516b99a7]{display:inline-block;outline:none;border:none;background:none;padding:.5rem .75rem;margin:.5rem 0;font-weight:700;cursor:pointer;border-radius:2rem;color:#8a8a8a}.slides .slide-navigation button[data-v-516b99a7]:hover{background:#87b82b;color:#fff}a.sidebar-link[data-v-15b7b770]:hover,a[data-v-15b7b770],a[data-v-15b7b770]:hover{color:#87b82b}a.sidebar-link.active[data-v-15b7b770]{color:#87b82b;border-left-color:#87b82b}figure[data-v-15b7b770]{display:flex;margin:0;padding:0;background:#eef0f3}figure.bordered[data-v-15b7b770]{border:1px solid #cecece}figure img[data-v-15b7b770]{display:block;margin:auto}.label[data-v-15b7b770]{display:inline-block;background:red;width:1rem;border-radius:1rem;height:1rem;line-height:1rem;font-size:.75rem;font-weight:700;color:#fff;padding-left:4px;box-sizing:border-box}.alert[data-v-15b7b770]{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem;line-height:1.7}.alert.alert-info[data-v-15b7b770]{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.definition[data-v-15b7b770]{line-height:1.7}table[data-v-15b7b770]{display:table;table-layout:auto;width:100%}.badge[data-v-15b7b770]{display:inline-block;font-size:14px;height:18px;line-height:18px;border-radius:3px;padding:0 6px;color:#fff}.badge.green[data-v-15b7b770],.badge.tip[data-v-15b7b770],.badge[data-v-15b7b770]{background-color:#42b983}.badge.error[data-v-15b7b770]{background-color:#da5961}.badge.warn[data-v-15b7b770],.badge.warning[data-v-15b7b770],.badge.yellow[data-v-15b7b770]{background-color:#e7c000}.badge+.badge[data-v-15b7b770]{margin-left:5px}.theme-code-block[data-v-759a7d02]{display:none}.theme-code-block__active[data-v-759a7d02]{display:block}.theme-code-block>pre[data-v-759a7d02]{background-color:orange}a.sidebar-link[data-v-deefee04]:hover,a[data-v-deefee04],a[data-v-deefee04]:hover{color:#87b82b}a.sidebar-link.active[data-v-deefee04]{color:#87b82b;border-left-color:#87b82b}figure[data-v-deefee04]{display:flex;margin:0;padding:0;background:#eef0f3}figure.bordered[data-v-deefee04]{border:1px solid #cecece}figure img[data-v-deefee04]{display:block;margin:auto}.label[data-v-deefee04]{display:inline-block;background:red;width:1rem;border-radius:1rem;height:1rem;line-height:1rem;font-size:.75rem;font-weight:700;color:#fff;padding-left:4px;box-sizing:border-box}.alert[data-v-deefee04]{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem;line-height:1.7}.alert.alert-info[data-v-deefee04]{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.definition[data-v-deefee04]{line-height:1.7}table[data-v-deefee04]{display:table;table-layout:auto;width:100%}.theme-code-group__nav[data-v-deefee04]{margin-bottom:-35px;background-color:#282c34;padding-bottom:22px;border-top-left-radius:6px;border-top-right-radius:6px;padding-left:10px;padding-top:10px}.theme-code-group__ul[data-v-deefee04]{margin:auto 0;padding-left:0;display:inline-flex;list-style:none}.theme-code-group__nav-tab[data-v-deefee04]{border:0;padding:5px;cursor:pointer;background-color:transparent;font-size:.85em;line-height:1.4;color:hsla(0,0%,100%,.9);font-weight:600}.theme-code-group__nav-tab-active[data-v-deefee04]{border-bottom:1px solid #42b983}.pre-blank[data-v-deefee04]{color:#42b983} \ No newline at end of file diff --git a/docs/contents/user-manual/introduction/assets/aal.jpg b/book/assets/img/aal.2862d53c.jpg similarity index 100% rename from docs/contents/user-manual/introduction/assets/aal.jpg rename to book/assets/img/aal.2862d53c.jpg diff --git a/docs/contents/user-manual/symbol-management/assets/actions-1.jpg b/book/assets/img/actions-1.a647260e.jpg similarity index 100% rename from docs/contents/user-manual/symbol-management/assets/actions-1.jpg rename to book/assets/img/actions-1.a647260e.jpg diff --git a/docs/contents/user-manual/symbol-management/assets/actions-2.jpg b/book/assets/img/actions-2.961474aa.jpg similarity index 100% rename from docs/contents/user-manual/symbol-management/assets/actions-2.jpg rename to book/assets/img/actions-2.961474aa.jpg diff --git a/docs/contents/user-manual/symbol-management/assets/actions-3.jpg b/book/assets/img/actions-3.f369fd0c.jpg similarity index 100% rename from docs/contents/user-manual/symbol-management/assets/actions-3.jpg rename to book/assets/img/actions-3.f369fd0c.jpg diff --git a/docs/contents/user-manual/best-practices/assets/auth-1.jpg b/book/assets/img/auth-1.61829e9e.jpg similarity index 100% rename from docs/contents/user-manual/best-practices/assets/auth-1.jpg rename to book/assets/img/auth-1.61829e9e.jpg diff --git a/docs/contents/user-manual/best-practices/assets/auth-2.jpg b/book/assets/img/auth-2.d62c103f.jpg similarity index 100% rename from docs/contents/user-manual/best-practices/assets/auth-2.jpg rename to book/assets/img/auth-2.d62c103f.jpg diff --git a/docs/contents/user-manual/learning/assets/counters-1.jpg b/book/assets/img/counters-1.cf7959f2.jpg similarity index 100% rename from docs/contents/user-manual/learning/assets/counters-1.jpg rename to book/assets/img/counters-1.cf7959f2.jpg diff --git a/docs/contents/user-manual/learning/assets/counters-2.jpg b/book/assets/img/counters-2.6932003d.jpg similarity index 100% rename from docs/contents/user-manual/learning/assets/counters-2.jpg rename to book/assets/img/counters-2.6932003d.jpg diff --git a/docs/contents/user-manual/learning/assets/counters-3.jpg b/book/assets/img/counters-3.a316388a.jpg similarity index 100% rename from docs/contents/user-manual/learning/assets/counters-3.jpg rename to book/assets/img/counters-3.a316388a.jpg diff --git a/docs/contents/user-manual/learning/assets/counters-4.jpg b/book/assets/img/counters-4.61a6bb76.jpg similarity index 100% rename from docs/contents/user-manual/learning/assets/counters-4.jpg rename to book/assets/img/counters-4.61a6bb76.jpg diff --git a/docs/contents/user-manual/project-management/assets/create-project.png b/book/assets/img/create-project.102669d3.png similarity index 100% rename from docs/contents/user-manual/project-management/assets/create-project.png rename to book/assets/img/create-project.102669d3.png diff --git a/docs/contents/dev-docs/development-docker/assets/docker-debug.png b/book/assets/img/docker-debug.f0cf1eeb.png similarity index 100% rename from docs/contents/dev-docs/development-docker/assets/docker-debug.png rename to book/assets/img/docker-debug.f0cf1eeb.png diff --git a/docs/contents/user-manual/project-management/assets/environments.png b/book/assets/img/environments.909cab90.png similarity index 100% rename from docs/contents/user-manual/project-management/assets/environments.png rename to book/assets/img/environments.909cab90.png diff --git a/docs/contents/user-manual/symbol-management/assets/export-1.jpg b/book/assets/img/export-1.4ab43898.jpg similarity index 100% rename from docs/contents/user-manual/symbol-management/assets/export-1.jpg rename to book/assets/img/export-1.4ab43898.jpg diff --git a/docs/contents/user-manual/symbol-management/assets/file-upload-1.jpg b/book/assets/img/file-upload-1.18599992.jpg similarity index 100% rename from docs/contents/user-manual/symbol-management/assets/file-upload-1.jpg rename to book/assets/img/file-upload-1.18599992.jpg diff --git a/docs/contents/user-manual/symbol-management/assets/file-upload-2.jpg b/book/assets/img/file-upload-2.9999a2fb.jpg similarity index 100% rename from docs/contents/user-manual/symbol-management/assets/file-upload-2.jpg rename to book/assets/img/file-upload-2.9999a2fb.jpg diff --git a/docs/contents/user-manual/symbol-management/assets/file-upload-3.jpg b/book/assets/img/file-upload-3.43a9e10c.jpg similarity index 100% rename from docs/contents/user-manual/symbol-management/assets/file-upload-3.jpg rename to book/assets/img/file-upload-3.43a9e10c.jpg diff --git a/docs/contents/user-manual/symbol-management/assets/import-1.jpg b/book/assets/img/import-1.20ad22e4.jpg similarity index 100% rename from docs/contents/user-manual/symbol-management/assets/import-1.jpg rename to book/assets/img/import-1.20ad22e4.jpg diff --git a/docs/contents/user-manual/learning/assets/learner-setup-1.png b/book/assets/img/learner-setup-1.063c1ff2.png similarity index 100% rename from docs/contents/user-manual/learning/assets/learner-setup-1.png rename to book/assets/img/learner-setup-1.063c1ff2.png diff --git a/docs/contents/user-manual/learning/assets/learner-setup-2.png b/book/assets/img/learner-setup-2.0d6cd1ae.png similarity index 100% rename from docs/contents/user-manual/learning/assets/learner-setup-2.png rename to book/assets/img/learner-setup-2.0d6cd1ae.png diff --git a/docs/contents/user-manual/learning/assets/learning-1.jpg b/book/assets/img/learning-1.d0fe7148.jpg similarity index 100% rename from docs/contents/user-manual/learning/assets/learning-1.jpg rename to book/assets/img/learning-1.d0fe7148.jpg diff --git a/docs/contents/user-manual/learning/assets/learning-2.jpg b/book/assets/img/learning-2.4595c3b7.jpg similarity index 100% rename from docs/contents/user-manual/learning/assets/learning-2.jpg rename to book/assets/img/learning-2.4595c3b7.jpg diff --git a/docs/contents/user-manual/best-practices/assets/learning-error.jpg b/book/assets/img/learning-error.9a3560ff.jpg similarity index 100% rename from docs/contents/user-manual/best-practices/assets/learning-error.jpg rename to book/assets/img/learning-error.9a3560ff.jpg diff --git a/docs/contents/dev-docs/development-docker/assets/live-reload.png b/book/assets/img/live-reload.1305d5df.png similarity index 100% rename from docs/contents/dev-docs/development-docker/assets/live-reload.png rename to book/assets/img/live-reload.1305d5df.png diff --git a/docs/contents/user-manual/user-management/assets/login.png b/book/assets/img/login.4df4819a.png similarity index 100% rename from docs/contents/user-manual/user-management/assets/login.png rename to book/assets/img/login.4df4819a.png diff --git a/website/assets/images/logo.png b/book/assets/img/logo.7d7a13bc.png similarity index 100% rename from website/assets/images/logo.png rename to book/assets/img/logo.7d7a13bc.png diff --git a/docs/contents/user-manual/user-management/assets/profile.png b/book/assets/img/profile.4c97bca5.png similarity index 100% rename from docs/contents/user-manual/user-management/assets/profile.png rename to book/assets/img/profile.4c97bca5.png diff --git a/docs/contents/user-manual/project-management/assets/project-list.png b/book/assets/img/project-list.69837016.png similarity index 100% rename from docs/contents/user-manual/project-management/assets/project-list.png rename to book/assets/img/project-list.69837016.png diff --git a/docs/contents/user-manual/learning/assets/results-compare-1.jpg b/book/assets/img/results-compare-1.9adc7c86.jpg similarity index 100% rename from docs/contents/user-manual/learning/assets/results-compare-1.jpg rename to book/assets/img/results-compare-1.9adc7c86.jpg diff --git a/docs/contents/user-manual/learning/assets/results-compare-2.jpg b/book/assets/img/results-compare-2.654497ba.jpg similarity index 100% rename from docs/contents/user-manual/learning/assets/results-compare-2.jpg rename to book/assets/img/results-compare-2.654497ba.jpg diff --git a/docs/contents/user-manual/learning/assets/results-compare-3.jpg b/book/assets/img/results-compare-3.0a6255d9.jpg similarity index 100% rename from docs/contents/user-manual/learning/assets/results-compare-3.jpg rename to book/assets/img/results-compare-3.0a6255d9.jpg diff --git a/docs/contents/user-manual/learning/assets/results-compare-4.jpg b/book/assets/img/results-compare-4.85ef950f.jpg similarity index 100% rename from docs/contents/user-manual/learning/assets/results-compare-4.jpg rename to book/assets/img/results-compare-4.85ef950f.jpg diff --git a/docs/contents/user-manual/learning/assets/resuming-1.jpg b/book/assets/img/resuming-1.4d6fa43e.jpg similarity index 100% rename from docs/contents/user-manual/learning/assets/resuming-1.jpg rename to book/assets/img/resuming-1.4d6fa43e.jpg diff --git a/docs/contents/user-manual/learning/assets/resuming-2.jpg b/book/assets/img/resuming-2.2c5ffbd8.jpg similarity index 100% rename from docs/contents/user-manual/learning/assets/resuming-2.jpg rename to book/assets/img/resuming-2.2c5ffbd8.jpg diff --git a/docs/contents/user-manual/learning/assets/resuming-3.jpg b/book/assets/img/resuming-3.9ce1f361.jpg similarity index 100% rename from docs/contents/user-manual/learning/assets/resuming-3.jpg rename to book/assets/img/resuming-3.9ce1f361.jpg diff --git a/docs/contents/user-manual/learning/assets/sample-1.jpg b/book/assets/img/sample-1.1e7bb236.jpg similarity index 100% rename from docs/contents/user-manual/learning/assets/sample-1.jpg rename to book/assets/img/sample-1.1e7bb236.jpg diff --git a/docs/contents/user-manual/learning/assets/sample-2.jpg b/book/assets/img/sample-2.09ccc5b9.jpg similarity index 100% rename from docs/contents/user-manual/learning/assets/sample-2.jpg rename to book/assets/img/sample-2.09ccc5b9.jpg diff --git a/book/assets/img/search.83621669.svg b/book/assets/img/search.83621669.svg new file mode 100644 index 000000000..03d83913e --- /dev/null +++ b/book/assets/img/search.83621669.svg @@ -0,0 +1 @@ + diff --git a/docs/contents/user-manual/learning/assets/statistics-1.jpg b/book/assets/img/statistics-1.3108a08a.jpg similarity index 100% rename from docs/contents/user-manual/learning/assets/statistics-1.jpg rename to book/assets/img/statistics-1.3108a08a.jpg diff --git a/docs/contents/user-manual/learning/assets/statistics-2.jpg b/book/assets/img/statistics-2.76aea7c6.jpg similarity index 100% rename from docs/contents/user-manual/learning/assets/statistics-2.jpg rename to book/assets/img/statistics-2.76aea7c6.jpg diff --git a/docs/contents/user-manual/learning/assets/statistics-3.jpg b/book/assets/img/statistics-3.678269c3.jpg similarity index 100% rename from docs/contents/user-manual/learning/assets/statistics-3.jpg rename to book/assets/img/statistics-3.678269c3.jpg diff --git a/docs/contents/user-manual/learning/assets/statistics-4.jpg b/book/assets/img/statistics-4.488847b3.jpg similarity index 100% rename from docs/contents/user-manual/learning/assets/statistics-4.jpg rename to book/assets/img/statistics-4.488847b3.jpg diff --git a/docs/contents/user-manual/symbol-management/assets/symbol-parameters-1.jpg b/book/assets/img/symbol-parameters-1.84e3bf86.jpg similarity index 100% rename from docs/contents/user-manual/symbol-management/assets/symbol-parameters-1.jpg rename to book/assets/img/symbol-parameters-1.84e3bf86.jpg diff --git a/docs/contents/user-manual/symbol-management/assets/symbol-parameters-2.jpg b/book/assets/img/symbol-parameters-2.ecb74dba.jpg similarity index 100% rename from docs/contents/user-manual/symbol-management/assets/symbol-parameters-2.jpg rename to book/assets/img/symbol-parameters-2.ecb74dba.jpg diff --git a/docs/contents/user-manual/symbol-management/assets/symbols-1.jpg b/book/assets/img/symbols-1.1ed50e85.jpg similarity index 100% rename from docs/contents/user-manual/symbol-management/assets/symbols-1.jpg rename to book/assets/img/symbols-1.1ed50e85.jpg diff --git a/docs/contents/user-manual/symbol-management/assets/symbols-archive.jpg b/book/assets/img/symbols-archive.7702ad2c.jpg similarity index 100% rename from docs/contents/user-manual/symbol-management/assets/symbols-archive.jpg rename to book/assets/img/symbols-archive.7702ad2c.jpg diff --git a/docs/contents/user-manual/symbol-management/assets/symbols-search.jpg b/book/assets/img/symbols-search.66841f44.jpg similarity index 100% rename from docs/contents/user-manual/symbol-management/assets/symbols-search.jpg rename to book/assets/img/symbols-search.66841f44.jpg diff --git a/docs/contents/user-manual/testing/assets/testing-1.jpg b/book/assets/img/testing-1.17a28805.jpg similarity index 100% rename from docs/contents/user-manual/testing/assets/testing-1.jpg rename to book/assets/img/testing-1.17a28805.jpg diff --git a/docs/contents/user-manual/testing/assets/testing-2.png b/book/assets/img/testing-2.ea98ea99.png similarity index 100% rename from docs/contents/user-manual/testing/assets/testing-2.png rename to book/assets/img/testing-2.ea98ea99.png diff --git a/docs/contents/user-manual/testing/assets/testing-3.jpg b/book/assets/img/testing-3.041c7f2f.jpg similarity index 100% rename from docs/contents/user-manual/testing/assets/testing-3.jpg rename to book/assets/img/testing-3.041c7f2f.jpg diff --git a/docs/contents/examples/todomvc/assets/todomvc-react.model.png b/book/assets/img/todomvc-react.model.cdf22921.png similarity index 100% rename from docs/contents/examples/todomvc/assets/todomvc-react.model.png rename to book/assets/img/todomvc-react.model.cdf22921.png diff --git a/docs/contents/examples/todomvc/assets/todomvc.jpg b/book/assets/img/todomvc.efca37f2.jpg similarity index 100% rename from docs/contents/examples/todomvc/assets/todomvc.jpg rename to book/assets/img/todomvc.efca37f2.jpg diff --git a/docs/contents/user-manual/user-management/assets/user-management.png b/book/assets/img/user-management.65603eb1.png similarity index 100% rename from docs/contents/user-manual/user-management/assets/user-management.png rename to book/assets/img/user-management.65603eb1.png diff --git a/docs/contents/user-manual/symbol-management/assets/variables-1.jpg b/book/assets/img/variables-1.ef01834f.jpg similarity index 100% rename from docs/contents/user-manual/symbol-management/assets/variables-1.jpg rename to book/assets/img/variables-1.ef01834f.jpg diff --git a/docs/contents/user-manual/symbol-management/assets/variables-2.jpg b/book/assets/img/variables-2.29ab7418.jpg similarity index 100% rename from docs/contents/user-manual/symbol-management/assets/variables-2.jpg rename to book/assets/img/variables-2.29ab7418.jpg diff --git a/docs/contents/user-manual/integrations/assets/webhooks-1.jpg b/book/assets/img/webhooks-1.f162c9e3.jpg similarity index 100% rename from docs/contents/user-manual/integrations/assets/webhooks-1.jpg rename to book/assets/img/webhooks-1.f162c9e3.jpg diff --git a/docs/contents/user-manual/integrations/assets/webhooks-2.jpg b/book/assets/img/webhooks-2.3c5fd584.jpg similarity index 100% rename from docs/contents/user-manual/integrations/assets/webhooks-2.jpg rename to book/assets/img/webhooks-2.3c5fd584.jpg diff --git a/docs/contents/user-manual/introduction/assets/workflow.png b/book/assets/img/workflow.9ad492ac.png similarity index 100% rename from docs/contents/user-manual/introduction/assets/workflow.png rename to book/assets/img/workflow.9ad492ac.png diff --git a/book/assets/js/10.93fb9a15.js b/book/assets/js/10.93fb9a15.js new file mode 100644 index 000000000..bf3432d9d --- /dev/null +++ b/book/assets/js/10.93fb9a15.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{394:function(t,s,i){},482:function(t,s,i){"use strict";i(394)},493:function(t,s,i){"use strict";i.r(s);var n={name:"Definition",props:["term"]},e=(i(482),i(65)),a=Object(e.a)(n,(function(){var t=this.$createElement,s=this._self._c||t;return s("div",{staticClass:"definition"},[s("span",{staticClass:"term"},[this._v(this._s(this.term))]),this._v(" "),this._t("default")],2)}),[],!1,null,"506a1a1b",null);s.default=a.exports}}]); \ No newline at end of file diff --git a/book/assets/js/11.f21bec4d.js b/book/assets/js/11.f21bec4d.js new file mode 100644 index 000000000..c9cd4b817 --- /dev/null +++ b/book/assets/js/11.f21bec4d.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{395:function(t,i,e){},483:function(t,i,e){"use strict";e(395)},494:function(t,i,e){"use strict";e.r(i);var s={name:"Slide",props:["title"],mounted:function(){var t=this.$el.querySelector("img"),i=t.src;t.src="",t.setAttribute("data-src",i),null!=this.title&&t.setAttribute("data-title",this.title)}},a=(e(483),e(65)),n=Object(a.a)(s,(function(){var t=this.$createElement,i=this._self._c||t;return i("div",{staticClass:"slide"},[i("div",{staticClass:"image"},[this._t("image")],2),this._v(" "),i("div",{staticClass:"text"},[this._t("text")],2)])}),[],!1,null,"20a7c7b2",null);i.default=n.exports}}]); \ No newline at end of file diff --git a/book/assets/js/12.6cb68f23.js b/book/assets/js/12.6cb68f23.js new file mode 100644 index 000000000..b094a23d0 --- /dev/null +++ b/book/assets/js/12.6cb68f23.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{398:function(t,e,n){},488:function(t,e,n){"use strict";n(398)},519:function(t,e,n){"use strict";n.r(e);var i={functional:!0,props:{type:{type:String,default:"tip"},text:String,vertical:{type:String,default:"top"}},render:function(t,e){var n=e.props,i=e.slots;return t("span",{class:["badge",n.type],style:{verticalAlign:n.vertical}},n.text||i().default)}},r=(n(488),n(65)),p=Object(r.a)(i,void 0,void 0,!1,null,"15b7b770",null);e.default=p.exports}}]); \ No newline at end of file diff --git a/book/assets/js/13.46597a4e.js b/book/assets/js/13.46597a4e.js new file mode 100644 index 000000000..d18784323 --- /dev/null +++ b/book/assets/js/13.46597a4e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{399:function(t,e,a){},489:function(t,e,a){"use strict";a(399)},496:function(t,e,a){"use strict";a.r(e);var n={name:"CodeBlock",props:{title:{type:String,required:!0},active:{type:Boolean,default:!1}},mounted:function(){this.$parent&&this.$parent.loadTabs&&this.$parent.loadTabs()}},i=(a(489),a(65)),s=Object(i.a)(n,(function(){var t=this.$createElement;return(this._self._c||t)("div",{staticClass:"theme-code-block",class:{"theme-code-block__active":this.active}},[this._t("default")],2)}),[],!1,null,"759a7d02",null);e.default=s.exports}}]); \ No newline at end of file diff --git a/book/assets/js/14.0ef0eaef.js b/book/assets/js/14.0ef0eaef.js new file mode 100644 index 000000000..f82b4be6e --- /dev/null +++ b/book/assets/js/14.0ef0eaef.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{400:function(e,t,a){},490:function(e,t,a){"use strict";a(400)},497:function(e,t,a){"use strict";a.r(t);a(93),a(43),a(9),a(96),a(97);var o={name:"CodeGroup",data:function(){return{codeTabs:[],activeCodeTabIndex:-1}},watch:{activeCodeTabIndex:function(e){this.activateCodeTab(e)}},mounted:function(){this.loadTabs()},methods:{changeCodeTab:function(e){this.activeCodeTabIndex=e},loadTabs:function(){var e=this;this.codeTabs=(this.$slots.default||[]).filter((function(e){return Boolean(e.componentOptions)})).map((function(t,a){return""===t.componentOptions.propsData.active&&(e.activeCodeTabIndex=a),{title:t.componentOptions.propsData.title,elm:t.elm}})),-1===this.activeCodeTabIndex&&this.codeTabs.length>0&&(this.activeCodeTabIndex=0),this.activateCodeTab(0)},activateCodeTab:function(e){this.codeTabs.forEach((function(e){e.elm&&e.elm.classList.remove("theme-code-block__active")})),this.codeTabs[e].elm&&this.codeTabs[e].elm.classList.add("theme-code-block__active")}}},n=(a(490),a(65)),c=Object(n.a)(o,(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ClientOnly",[a("div",{staticClass:"theme-code-group"},[a("div",{staticClass:"theme-code-group__nav"},[a("ul",{staticClass:"theme-code-group__ul"},e._l(e.codeTabs,(function(t,o){return a("li",{key:t.title,staticClass:"theme-code-group__li"},[a("button",{staticClass:"theme-code-group__nav-tab",class:{"theme-code-group__nav-tab-active":o===e.activeCodeTabIndex},on:{click:function(t){return e.changeCodeTab(o)}}},[e._v("\n "+e._s(t.title)+"\n ")])])})),0)]),e._v(" "),e._t("default"),e._v(" "),e.codeTabs.length<1?a("pre",{staticClass:"pre-blank"},[e._v("// Make sure to add code blocks to your code group")]):e._e()],2)])}),[],!1,null,"deefee04",null);t.default=c.exports}}]); \ No newline at end of file diff --git a/book/assets/js/15.d8927f63.js b/book/assets/js/15.d8927f63.js new file mode 100644 index 000000000..2b7220b86 --- /dev/null +++ b/book/assets/js/15.d8927f63.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{426:function(e,t,o){e.exports=o.p+"assets/img/docker-debug.f0cf1eeb.png"},427:function(e,t,o){e.exports=o.p+"assets/img/live-reload.1305d5df.png"},502:function(e,t,o){"use strict";o.r(t);var r=o(65),a=Object(r.a)({},(function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("h1",{attrs:{id:"development-docker"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#development-docker"}},[e._v("#")]),e._v(" Development (Docker)")]),e._v(" "),r("h2",{attrs:{id:"requirements"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#requirements"}},[e._v("#")]),e._v(" Requirements")]),e._v(" "),r("p",[e._v("To run ALEX, install the following software on your machine:")]),e._v(" "),r("p",[r("strong",[e._v("Linux")])]),e._v(" "),r("ul",[r("li",[e._v("Docker (v20.10.*) and")]),e._v(" "),r("li",[e._v("Docker Compose (v1.28.*)")])]),e._v(" "),r("p",[r("strong",[e._v("Windows / Mac")])]),e._v(" "),r("ul",[r("li",[e._v("Docker for Windows")])]),e._v(" "),r("h2",{attrs:{id:"installation"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[e._v("#")]),e._v(" Installation")]),e._v(" "),r("p",[r("strong",[e._v("Windows, Linux, Mac (Intel)")])]),e._v(" "),r("ol",[r("li",[e._v("Clone the repository.")]),e._v(" "),r("li",[e._v("Run "),r("code",[e._v("docker-compose -f docker-compose.develop.yml pull")]),e._v(".")]),e._v(" "),r("li",[e._v("Run "),r("code",[e._v("docker-compose -f docker-compose.develop.yml up")]),e._v(".")]),e._v(" "),r("li",[e._v("Open "),r("code",[e._v("http://127.0.0.1:4200/")]),e._v(" in a web browser to access the frontend.")])]),e._v(" "),r("p",[r("strong",[e._v("Mac (ARM)")])]),e._v(" "),r("ol",[r("li",[e._v("Clone the repository.")]),e._v(" "),r("li",[e._v("Run "),r("code",[e._v("docker-compose -f docker-compose.develop.yml -f docker-compose.overrides.m1.yml pull")]),e._v(".")]),e._v(" "),r("li",[e._v("Run "),r("code",[e._v("docker-compose -f docker-compose.develop.yml -f docker-compose.overrides.m1.yml up")]),e._v(".")]),e._v(" "),r("li",[e._v("Open "),r("code",[e._v("http://127.0.0.1:4200/")]),e._v(" in a web browser to access the frontend.")])]),e._v(" "),r("h2",{attrs:{id:"credentials"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#credentials"}},[e._v("#")]),e._v(" Credentials")]),e._v(" "),r("p",[e._v("After the first start, you can log in as an admin using the account below:")]),e._v(" "),r("p",[e._v("Email: "),r("em",[e._v("admin@alex.example")]),e._v(" "),r("br"),e._v("\nPassword: "),r("em",[e._v("admin")])]),e._v(" "),r("h2",{attrs:{id:"services"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#services"}},[e._v("#")]),e._v(" Services")]),e._v(" "),r("table",[r("thead",[r("tr",[r("th",[e._v("Port")]),e._v(" "),r("th",[e._v("Service")])])]),e._v(" "),r("tbody",[r("tr",[r("td",[e._v("4200")]),e._v(" "),r("td",[e._v("Frontend (with live reload)")])]),e._v(" "),r("tr",[r("td",[e._v("8000")]),e._v(" "),r("td",[e._v("API")])]),e._v(" "),r("tr",[r("td",[e._v("5005")]),e._v(" "),r("td",[e._v("API Debug Port")])]),e._v(" "),r("tr",[r("td",[e._v("4444")]),e._v(" "),r("td",[e._v("Selenium Hub")])]),e._v(" "),r("tr",[r("td",[e._v("7901")]),e._v(" "),r("td",[e._v("Chrome VNC (open in browser)")])]),e._v(" "),r("tr",[r("td",[e._v("7901")]),e._v(" "),r("td",[e._v("Firefox VNC (open in browser)")])])])]),e._v(" "),r("p",[e._v("For both, the Chrome and the Firefox VNC server, you can use the password "),r("code",[e._v("secret")]),e._v(".")]),e._v(" "),r("h2",{attrs:{id:"backend-debugging"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#backend-debugging"}},[e._v("#")]),e._v(" Backend debugging")]),e._v(" "),r("p",[e._v("You can debug the backend of ALEX from within Docker.\nIn this case, we use IntelliJ to connect to the remote debugger.\nTherefore, create a new run configuration.\nGo to "),r("code",[e._v("Run")]),e._v(", "),r("code",[e._v("Edit Configurations...")]),e._v(", add a new configuration of type "),r("code",[e._v("Remote JVM Debug")]),e._v(" and configure it according the following image:")]),e._v(" "),r("p",[r("img",{attrs:{src:o(426),alt:"Docker debug"}})]),e._v(" "),r("p",[e._v("Then, start ALEX via the "),r("code",[e._v("docker-compose.develop.yml")]),e._v(", wait until the application is started and run the created configuration.")]),e._v(" "),r("h2",{attrs:{id:"backend-live-reload"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#backend-live-reload"}},[e._v("#")]),e._v(" Backend live reload")]),e._v(" "),r("p",[e._v("Thanks to Spring devtools, we can leverage the live reload capability to restart the application automatically as soon as the code changes.\nTherefore, create a new run configuration.\nGo to "),r("code",[e._v("Run")]),e._v(", "),r("code",[e._v("Edit Configurations...")]),e._v(", add a new configuration of type "),r("code",[e._v("Application")]),e._v(" and configure it according the following image:")]),e._v(" "),r("p",[r("img",{attrs:{src:o(427),alt:"Live reload"}})]),e._v(" "),r("p",[e._v("Then, start ALEX via the "),r("code",[e._v("docker-compose.develop.yml")]),e._v(", wait until the application is started and run the created configuration.\nNow you can make changes in the Java files, rebuild the module (e.g. via "),r("code",[e._v("STRG+Shift+F9")]),e._v(") and the application is rebuild inside the container.")])])}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file diff --git a/book/assets/js/16.cda6f9ed.js b/book/assets/js/16.cda6f9ed.js new file mode 100644 index 000000000..443da6fa9 --- /dev/null +++ b/book/assets/js/16.cda6f9ed.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{428:function(e,t,o){e.exports=o.p+"assets/img/todomvc.efca37f2.jpg"},429:function(e,t,o){e.exports=o.p+"assets/img/todomvc-react.model.cdf22921.png"},507:function(e,t,o){"use strict";o.r(t);var r=o(65),a=Object(r.a)({},(function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("p",[r("img",{attrs:{src:o(428),alt:"TodoMVC"}})]),e._v(" "),r("h1",{attrs:{id:"todomvc"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#todomvc"}},[e._v("#")]),e._v(" TodoMVC")]),e._v(" "),r("p",[e._v("In this section, we present the steps in order to learn the "),r("em",[e._v("ReactJS")]),e._v(" implementation of the "),r("a",{attrs:{href:"http://todomvc.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("TodoMVC"),r("OutboundLink")],1),e._v(" project.")]),e._v(" "),r("h2",{attrs:{id:"requirements"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#requirements"}},[e._v("#")]),e._v(" Requirements")]),e._v(" "),r("ul",[r("li",[e._v("ALEX v3.0.0")]),e._v(" "),r("li",[r("a",{attrs:{href:"http://todomvc.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("TodoMVC"),r("OutboundLink")],1),e._v(" v1.3")])]),e._v(" "),r("h2",{attrs:{id:"instructions"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#instructions"}},[e._v("#")]),e._v(" Instructions")]),e._v(" "),r("p",[e._v("Follow the instructions on the "),r("a",{attrs:{href:"http://todomvc.com/",target:"_blank",rel:"noopener noreferrer"}},[e._v("homepage"),r("OutboundLink")],1),e._v(" of TodoMVC in order to start the application.\nIn the following, we assume that TodoMVC runs on port 8080 and is accessible at "),r("em",[e._v("http://localhost:8080/")]),e._v(".")]),e._v(" "),r("h3",{attrs:{id:"_1-import-the-project"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#_1-import-the-project"}},[e._v("#")]),e._v(" 1) Import the project")]),e._v(" "),r("ol",[r("li",[e._v("Download the exported project "),r("a",{attrs:{href:"/files/todomvc-react.project.json"}},[e._v("here")]),e._v(".")]),e._v(" "),r("li",[e._v("In the project overview, click on the import icon in the action bar and select the project in the file "),r("em",[e._v("todomvc-react.project.json")])]),e._v(" "),r("li",[e._v("Open the project by clicking on the corresponding item in the list.")])]),e._v(" "),r("h3",{attrs:{id:"_2-learn-todomvc"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#_2-learn-todomvc"}},[e._v("#")]),e._v(" 2) Learn TodoMVC")]),e._v(" "),r("h4",{attrs:{id:"with-a-new-setup"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#with-a-new-setup"}},[e._v("#")]),e._v(" With a new setup")]),e._v(" "),r("ol",[r("li",[e._v("Click on "),r("em",[e._v("Learning")]),e._v(" > "),r("em",[e._v("Setups")]),e._v(" in the sidebar.")]),e._v(" "),r("li",[e._v("Click on "),r("em",[e._v("New Setup")])]),e._v(" "),r("li",[e._v("For the reset symbol, select the symbol "),r("em",[e._v("reset")]),e._v(".")]),e._v(" "),r("li",[e._v("For the input alphabet, select all symbols except "),r("em",[e._v("reset")]),e._v(" from the panel "),r("em",[e._v("Symbols")]),e._v(" on the left.")]),e._v(" "),r("li",[e._v("The symbols "),r("em",[e._v("create todo")]),e._v(", "),r("em",[e._v("delete todo")]),e._v(" and "),r("em",[e._v("toggle completed")]),e._v(" have parameter "),r("em",[e._v("text")]),e._v('.\nInsert any value for each them, e.g. "bananas".')]),e._v(" "),r("li",[e._v('In the configuration panel on the right, select the TTT algorithm.\nUse a "Random Word" Equivalence Oracle with the parameters (Min length = 60, Max length = 60, Random words = 60, Batch size = 1).')]),e._v(" "),r("li",[e._v("In the "),r("em",[e._v("WebDriver")]),e._v(" tab, select the desired browser.")]),e._v(" "),r("li",[e._v("Click on "),r("em",[e._v("Run")]),e._v(" to run the experiment.")])]),e._v(" "),r("h4",{attrs:{id:"with-the-existing-setup"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#with-the-existing-setup"}},[e._v("#")]),e._v(" With the existing setup")]),e._v(" "),r("p",[e._v("For demonstration purposes, the project already contains a predefined learner setup ready to use.\nThe setup uses the same parameters as in the previous section and executes tests in Chrome.")]),e._v(" "),r("ol",[r("li",[e._v("Click on "),r("em",[e._v("Learning")]),e._v(" > "),r("em",[e._v("Setups")]),e._v(" in the sidebar.\nThe predefined setup is called "),r("em",[e._v('"setup with one todo item"')])]),e._v(" "),r("li",[e._v("Click on "),r("em",[e._v("Run")]),e._v(".")])]),e._v(" "),r("h2",{attrs:{id:"results"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#results"}},[e._v("#")]),e._v(" Results")]),e._v(" "),r("p",[e._v("Depending on the hardware specifications of the system that the process is running on, the execution time may vary.\nFor this example, the process has been executed on a Laptop with an Intel Core i7 8th Gen, 32GB RAM and an SSD.\nThe execution took 9min45s and the following model has been learned:")]),e._v(" "),r("p",[r("img",{attrs:{src:o(429),alt:"TodoMVC"}}),e._v("\nDownload the DOT file "),r("a",{attrs:{href:"/files/todomvc-react.model.json"}},[e._v("here")]),e._v(".")])])}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file diff --git a/book/assets/js/17.1c73b199.js b/book/assets/js/17.1c73b199.js new file mode 100644 index 000000000..be45ba2d0 --- /dev/null +++ b/book/assets/js/17.1c73b199.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[17],{432:function(e,t,s){e.exports=s.p+"assets/img/webhooks-1.f162c9e3.jpg"},433:function(e,t,s){e.exports=s.p+"assets/img/webhooks-2.3c5fd584.jpg"},511:function(e,t,s){"use strict";s.r(t);var n=s(65),o=Object(n.a)({},(function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[n("h1",{attrs:{id:"integrations"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#integrations"}},[e._v("#")]),e._v(" Integrations")]),e._v(" "),n("p",[e._v("ALEX offers some ways for integration in third party applications.")]),e._v(" "),n("h2",{attrs:{id:"webhooks"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#webhooks"}},[e._v("#")]),e._v(" Webhooks")]),e._v(" "),n("p",[n("a",{attrs:{href:"https://en.wikipedia.org/wiki/Webhook",target:"_blank",rel:"noopener noreferrer"}},[e._v("Webhooks"),n("OutboundLink")],1),e._v(" are a way to let third party applications know about events that happen in a system.\nThese applications have to register a hook by specifying a URL.\nWhen an internal event occurs, e.g. a learning process is finished, ALEX sends an HTTP request to the registered URL.\nIf a body is send along the HTTP request, it is formatted as JSON object.")]),e._v(" "),n("div",{staticClass:"alert alert-info"},[e._v("\n Currently, if the target server cannot be reached within 3 seconds, the request is cancelled.\n ALEX also does not provide a retry mechanism at the moment.\n")]),e._v(" "),n("p",[n("img",{attrs:{src:s(432),alt:"Webhooks"}})]),e._v(" "),n("p",[e._v("Webhooks are managed under the "),n("strong",[e._v("Integrations > Webhooks")]),e._v(" item in the sidebar.\nOn the page a list of registered webhooks is displayed.")]),e._v(" "),n("p",[n("img",{attrs:{src:s(433),alt:"Webhooks"}})]),e._v(" "),n("p",[e._v("To create a new webhook, click on the "),n("strong",[e._v("Create")]),e._v("-button.\nIn the dialog, specify the following properties in the modal dialog:")]),e._v(" "),n("table",[n("thead",[n("tr",[n("th",[e._v("Property")]),e._v(" "),n("th",[e._v("Description")]),e._v(" "),n("th",[e._v("Required")])])]),e._v(" "),n("tbody",[n("tr",[n("td",[e._v("Name")]),e._v(" "),n("td",[e._v("The name of the webhook, e.g. the name of the service.")]),e._v(" "),n("td",[e._v("no")])]),e._v(" "),n("tr",[n("td",[e._v("URL")]),e._v(" "),n("td",[e._v("The URL where events are send to.")]),e._v(" "),n("td",[e._v("yes")])]),e._v(" "),n("tr",[n("td",[e._v("Events")]),e._v(" "),n("td",[e._v("The list of subscribed events.")]),e._v(" "),n("td",[e._v("yes")])])])]),e._v(" "),n("p",[e._v("There are numerous events for all kind of actions that are performed in ALEX internally.\nThe names of the events should be self explaining.\nFor almost all events, the corresponding entity that the event deals with is send as a JSON object to the registered endpoint.\nOnly for "),n("em",[e._v("... deleted")]),e._v(" events, the ID of the entity is send to the client.")])])}),[],!1,null,null,null);t.default=o.exports}}]); \ No newline at end of file diff --git a/book/assets/js/18.4ea060e5.js b/book/assets/js/18.4ea060e5.js new file mode 100644 index 000000000..c507842e7 --- /dev/null +++ b/book/assets/js/18.4ea060e5.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[18],{434:function(e,t,a){e.exports=a.p+"assets/img/aal.2862d53c.jpg"},435:function(e,t,a){e.exports=a.p+"assets/img/workflow.9ad492ac.png"},512:function(e,t,a){"use strict";a.r(t);var n=a(65),i=Object(n.a)({},(function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[n("h1",{attrs:{id:"user-manual"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#user-manual"}},[e._v("#")]),e._v(" User manual")]),e._v(" "),n("p",[e._v("Here and in the following sections, we present a detailed explanation of the concepts and ways to use ALEX.\nIf you find bugs of any kind relating this application or inaccuracies in this manual, "),n("a",{attrs:{href:"mailto:alexander.bainczyk@tu-dortmund.de,marco.krumrey@tu-dortmund.de"}},[e._v("let us")]),e._v(" know.")]),e._v(" "),n("h2",{attrs:{id:"features"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#features"}},[e._v("#")]),e._v(" Features")]),e._v(" "),n("p",[e._v("ALEX offers a simplicity-oriented way to execute learning experiments for web applications and web services using active automata learning.\nSince version 1.5.0 ALEX has been extended to support traditional UI and interface testing using Selenium as well.\nBased on features of "),n("a",{attrs:{href:"https://learnlib.de/",target:"_blank",rel:"noopener noreferrer"}},[e._v("LearnLib"),n("OutboundLink")],1),e._v(", ALEX lays a focus on the ease to use of the tool while offering an extensive feature set, including:")]),e._v(" "),n("ul",[n("li",[e._v("Inferring Mealy machines of web applications and web services using active automata learning techniques")]),e._v(" "),n("li",[e._v("Graphical symbol and learning process modelling")]),e._v(" "),n("li",[e._v("Automatic generation and visualization of\n"),n("ul",[n("li",[e._v("Models")]),e._v(" "),n("li",[e._v("Algorithmic data structures (observation table and discrimination tree)")]),e._v(" "),n("li",[e._v("Statistics of learning experiments")])])]),e._v(" "),n("li",[e._v("Simultaneous learning of web applications and web services")]),e._v(" "),n("li",[e._v("Various learning algorithms and equivalence approximation strategies")]),e._v(" "),n("li",[e._v("LTL-based model checking")]),e._v(" "),n("li",[e._v("GUI testing capabilities")]),e._v(" "),n("li",[e._v("And much more...")])]),e._v(" "),n("h2",{attrs:{id:"required-skills"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#required-skills"}},[e._v("#")]),e._v(" Required skills")]),e._v(" "),n("p",[e._v("As a user of ALEX and tester of web applications, you should")]),e._v(" "),n("ul",[n("li",[e._v("be familiar with HTML and CSS")]),e._v(" "),n("li",[e._v("be familiar with REST interfaces and exchange formats like JSON")]),e._v(" "),n("li",[e._v("have a basic understanding of web application testing")]),e._v(" "),n("li",[e._v("have a basic understanding of active automata learning")])]),e._v(" "),n("p",[e._v("It helps if you are familiar with programming in general and have already used Selenium.")]),e._v(" "),n("h2",{attrs:{id:"terminology"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#terminology"}},[e._v("#")]),e._v(" Terminology")]),e._v(" "),n("p",[e._v("This document contains some terms related to automata learning which are listed in the following:")]),e._v(" "),n("definition",{attrs:{term:"System under Learning (SUL)"}},[e._v("\n The system we want to infer an automaton model from.\n Often also called system under testing (SUT).\n")]),e._v(" "),n("definition",{attrs:{term:"Symbol"}},[e._v("\n We differentiate between input and output symbols.\n Input symbols are modeled by the user and define possible inputs to a system, like a click.\n Output symbols specify how the system reacts to inputs.\n")]),e._v(" "),n("definition",{attrs:{term:"Word"}},[e._v("\n A sequence of symbols, e.g. "),n("em",[e._v("Authenticate, Create Entity, Read Entity, Delete Entity, Logout")]),e._v(".\n")]),e._v(" "),n("definition",{attrs:{term:"Learner"}},[e._v("\n A learner is an algorithm that infers an automaton model of an application by posing words to the SUL and analyzing its outputs.\n")]),e._v(" "),n("definition",{attrs:{term:"Membership query"}},[e._v("\n The words the learner poses to the system are called membership queries.\n")]),e._v(" "),n("definition",{attrs:{term:"Equivalence query"}},[e._v("\n An equivalence query is posed by an equivalence oracle. \n It checks whether the learned automaton represents the behavior of the tested application correctly.\n")]),e._v(" "),n("definition",{attrs:{term:"Hypothesis"}},[e._v("\n A hypothesis is the behavioral automaton model that is learned.\n The model is called hypothesis due to the black-box nature of the SUL. \n Theoretically, there can always exist a behavior that is not captured by the model.\n")]),e._v(" "),n("definition",{attrs:{term:"Counterexample"}},[e._v("\n A counterexample is a word, where the output of the system and the learned model differ.\n Counterexamples are used to trigger the refinement of the model.\n We call a model the "),n("em",[e._v("final hypothesis")]),e._v(", if no counterexamples can be found.\n")]),e._v(" "),n("p",[e._v("The following graphic illustrates the general learning process and thus the relation between the terms listed above.")]),e._v(" "),n("img",{staticStyle:{display:"block",width:"70%",margin:"auto"},attrs:{src:a(434)}}),e._v(" "),n("h2",{attrs:{id:"workflow"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#workflow"}},[e._v("#")]),e._v(" Workflow")]),e._v(" "),n("p",[e._v("ALEX covers all aspects of "),n("em",[e._v("learning-based testing")]),e._v(".\nThe following diagram illustrates how the tool supports learning, testing and model checking of web applications.")]),e._v(" "),n("img",{staticStyle:{display:"block",width:"100%",margin:"auto"},attrs:{src:a(435)}})],1)}),[],!1,null,null,null);t.default=i.exports}}]); \ No newline at end of file diff --git a/book/assets/js/19.4a11ac03.js b/book/assets/js/19.4a11ac03.js new file mode 100644 index 000000000..979054165 --- /dev/null +++ b/book/assets/js/19.4a11ac03.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[19],{425:function(e,t,a){e.exports=a.p+"assets/img/logo.7d7a13bc.png"},498:function(e,t,a){"use strict";a.r(t);var r=a(65),n=Object(r.a)({},(function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("figure",[r("img",{staticStyle:{"max-width":"320px",margin:"2rem auto",display:"block"},attrs:{src:a(425)}})]),e._v(" "),r("h1",{attrs:{id:"alex"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#alex"}},[e._v("#")]),e._v(" ALEX")]),e._v(" "),r("p",[e._v("Automata Learning EXperience (ALEX) allows you run automated tests on Web applications and HTTP-based APIs using active automata learning.")]),e._v(" "),r("p",[e._v("Users model "),r("a",{attrs:{href:"https://www.seleniumhq.org/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Selenium"),r("OutboundLink")],1),e._v("- or HTTP-based test inputs for their target application, which are used to automatically infer an automaton model (a "),r("a",{attrs:{href:"https://en.wikipedia.org/wiki/Mealy_machine",target:"_blank",rel:"noopener noreferrer"}},[e._v("Mealy machine"),r("OutboundLink")],1),e._v(") by learning algorithms.\nThe resulting automaton represents the user-level behavior of the web application which can be verified by LTL formulas.")])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/book/assets/js/2.3b539fe4.js b/book/assets/js/2.3b539fe4.js new file mode 100644 index 000000000..3f32b642f --- /dev/null +++ b/book/assets/js/2.3b539fe4.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[2],{367:function(t,e,n){"use strict";n.d(e,"d",(function(){return i})),n.d(e,"a",(function(){return a})),n.d(e,"i",(function(){return s})),n.d(e,"f",(function(){return u})),n.d(e,"g",(function(){return l})),n.d(e,"h",(function(){return c})),n.d(e,"b",(function(){return h})),n.d(e,"e",(function(){return f})),n.d(e,"k",(function(){return p})),n.d(e,"l",(function(){return d})),n.d(e,"c",(function(){return v})),n.d(e,"j",(function(){return m}));n(32),n(94),n(368),n(124),n(370),n(201),n(93),n(96),n(9),n(97),n(43),n(127),n(195);var i=/#.*$/,r=/\.(md|html)$/,a=/\/$/,s=/^[a-z]+:/i;function o(t){return decodeURI(t).replace(i,"").replace(r,"")}function u(t){return s.test(t)}function l(t){return/^mailto:/.test(t)}function c(t){return/^tel:/.test(t)}function h(t){if(u(t))return t;var e=t.match(i),n=e?e[0]:"",r=o(t);return a.test(r)?t:r+".html"+n}function f(t,e){var n=decodeURIComponent(t.hash),r=function(t){var e=t.match(i);if(e)return e[0]}(e);return(!r||n===r)&&o(t.path)===o(e)}function p(t,e,n){if(u(e))return{type:"external",path:e};n&&(e=function(t,e,n){var i=t.charAt(0);if("/"===i)return t;if("?"===i||"#"===i)return e+t;var r=e.split("/");n&&r[r.length-1]||r.pop();for(var a=t.replace(/^\//,"").split("/"),s=0;s3&&void 0!==arguments[3]?arguments[3]:1;if("string"==typeof e)return p(n,e,i);if(Array.isArray(e))return Object.assign(p(n,e[0],i),{title:e[1]});var a=e.children||[];return 0===a.length&&e.path?Object.assign(p(n,e.path,i),{title:e.title}):{type:"group",path:e.path,title:e.title,sidebarDepth:e.sidebarDepth,initialOpenGroupIndex:e.initialOpenGroupIndex,children:a.map((function(e){return t(e,n,i,r+1)})),collapsable:!1!==e.collapsable}}(t,r,l)})):[]}return[]}function g(t){var e=v(t.headers||[]);return[{type:"group",collapsable:!1,title:t.title,path:null,children:e.map((function(e){return{type:"auto",title:e.title,basePath:t.path,path:t.path+"#"+e.slug,children:e.children||[]}}))}]}function v(t){var e;return(t=t.map((function(t){return Object.assign({},t)}))).forEach((function(t){2===t.level?e=t:e&&(e.children||(e.children=[])).push(t)})),t.filter((function(t){return 2===t.level}))}function m(t){return Object.assign(t,{type:t.items&&t.items.length?"links":"link"})}},368:function(t,e,n){"use strict";var i=n(6),r=n(198),a=n(11),s=n(95),o=n(17),u=n(33),l=n(66),c=n(199),h=n(200);r("match",(function(t,e,n){return[function(e){var n=u(this),r=null==e?void 0:l(e,t);return r?i(r,e,n):new RegExp(e)[t](o(n))},function(t){var i=a(this),r=o(t),u=n(e,i,r);if(u.done)return u.value;if(!i.global)return h(i,r);var l=i.unicode;i.lastIndex=0;for(var f,p=[],d=0;null!==(f=h(i,r));){var g=o(f[0]);p[d]=g,""===g&&(i.lastIndex=c(r,s(i.lastIndex),l)),d++}return 0===d?null:p}]}))},369:function(t,e){t.exports="\t\n\v\f\r                 \u2028\u2029\ufeff"},370:function(t,e,n){"use strict";var i=n(44),r=n(6),a=n(3),s=n(198),o=n(196),u=n(11),l=n(33),c=n(130),h=n(199),f=n(95),p=n(17),d=n(66),g=n(205),v=n(200),m=n(99),b=n(194),k=n(2),_=b.UNSUPPORTED_Y,x=Math.min,y=[].push,C=a(/./.exec),$=a(y),L=a("".slice);s("split",(function(t,e,n){var a;return a="c"=="abbc".split(/(b)*/)[1]||4!="test".split(/(?:)/,-1).length||2!="ab".split(/(?:ab)*/).length||4!=".".split(/(.?)(.?)/).length||".".split(/()()/).length>1||"".split(/.?/).length?function(t,n){var a=p(l(this)),s=void 0===n?4294967295:n>>>0;if(0===s)return[];if(void 0===t)return[a];if(!o(t))return r(e,a,t,s);for(var u,c,h,f=[],d=(t.ignoreCase?"i":"")+(t.multiline?"m":"")+(t.unicode?"u":"")+(t.sticky?"y":""),v=0,b=new RegExp(t.source,d+"g");(u=r(m,b,a))&&!((c=b.lastIndex)>v&&($(f,L(a,v,u.index)),u.length>1&&u.index=s));)b.lastIndex===u.index&&b.lastIndex++;return v===a.length?!h&&C(b,"")||$(f,""):$(f,L(a,v)),f.length>s?g(f,0,s):f}:"0".split(void 0,0).length?function(t,n){return void 0===t&&0===n?[]:r(e,this,t,n)}:e,[function(e,n){var i=l(this),s=null==e?void 0:d(e,t);return s?r(s,e,i,n):r(a,p(i),e,n)},function(t,i){var r=u(this),s=p(t),o=n(a,r,s,i,a!==e);if(o.done)return o.value;var l=c(r,RegExp),d=r.unicode,g=(r.ignoreCase?"i":"")+(r.multiline?"m":"")+(r.unicode?"u":"")+(_?"g":"y"),m=new l(_?"^(?:"+r.source+")":r,g),b=void 0===i?4294967295:i>>>0;if(0===b)return[];if(0===s.length)return null===v(m,s)?[s]:[];for(var k=0,y=0,C=[];y@^][^\s!#%&*+<=>@^]*>/,P=/a/g,N=/a/g,A=new L(P)!==P,D=d.MISSED_STICKY,U=d.UNSUPPORTED_Y,H=i&&(!A||D||y||C||m((function(){return N[$]=!1,L(P)!=P||L(N)==N||"/a/i"!=L(P,"i")})));if(s("RegExp",H)){for(var W=function(t,e){var n,i,r,a,s,l,d=c(w,this),g=h(t),v=void 0===e,m=[],_=t;if(!d&&g&&v&&t.constructor===W)return t;if((g||c(w,t))&&(t=t.source,v&&(e=p(_))),t=void 0===t?"":f(t),e=void 0===e?"":f(e),_=t,y&&"dotAll"in P&&(i=!!e&&j(e,"s")>-1)&&(e=E(e,/s/g,"")),n=e,D&&"sticky"in P&&(r=!!e&&j(e,"y")>-1)&&U&&(e=E(e,/y/g,"")),C&&(t=(a=function(t){for(var e,n=t.length,i=0,r="",a=[],s={},o=!1,u=!1,l=0,c="";i<=n;i++){if("\\"===(e=I(t,i)))e+=I(t,++i);else if("]"===e)o=!1;else if(!o)switch(!0){case"["===e:o=!0;break;case"("===e:S(T,R(t,i+1))&&(i+=2,u=!0),r+=e,l++;continue;case">"===e&&u:if(""===c||b(s,c))throw new O("Invalid capture group name");s[c]=!0,a[a.length]=[c,l],u=!1,c="";continue}u?c+=e:r+=e}return[r,a]}(t))[0],m=a[1]),s=o(L(t,e),d?this:w,W),(i||r||m.length)&&(l=k(s),i&&(l.dotAll=!0,l.raw=W(function(t){for(var e,n=t.length,i=0,r="",a=!1;i<=n;i++)"\\"!==(e=I(t,i))?a||"."!==e?("["===e?a=!0:"]"===e&&(a=!1),r+=e):r+="[\\s\\S]":r+=e+I(t,++i);return r}(t),n)),r&&(l.sticky=!0),m.length&&(l.groups=m)),t!==_)try{u(s,"source",""===_?"(?:)":_)}catch(t){}return s},G=l(L),B=0;G.length>B;)g(W,L,G[B++]);w.constructor=W,W.prototype=w,v(r,"RegExp",W,{constructor:!0})}_("RegExp")},375:function(t,e,n){var i=n(6),r=n(10),a=n(35),s=n(208),o=RegExp.prototype;t.exports=function(t){var e=t.flags;return void 0!==e||"flags"in o||r(t,"flags")||!a(o,t)?e:i(s,t)}},376:function(t,e,n){var i=n(0),r=n(8),a=n(197),s=n(25),o=n(377),u=n(34).get,l=RegExp.prototype,c=i.TypeError;r&&a&&o(l,"dotAll",{configurable:!0,get:function(){if(this!==l){if("RegExp"===s(this))return!!u(this).dotAll;throw c("Incompatible receiver, RegExp required")}}})},377:function(t,e,n){var i=n(202),r=n(12);t.exports=function(t,e,n){return n.get&&i(n.get,e,{getter:!0}),n.set&&i(n.set,e,{setter:!0}),r.f(t,e,n)}},378:function(t,e,n){var i=n(0),r=n(8),a=n(194).MISSED_STICKY,s=n(25),o=n(377),u=n(34).get,l=RegExp.prototype,c=i.TypeError;r&&a&&o(l,"sticky",{configurable:!0,get:function(){if(this!==l){if("RegExp"===s(this))return!!u(this).sticky;throw c("Incompatible receiver, RegExp required")}}})},379:function(t,e,n){"use strict";var i=n(98).PROPER,r=n(15),a=n(11),s=n(17),o=n(2),u=n(375),l=RegExp.prototype.toString,c=o((function(){return"/a/b"!=l.call({source:"a",flags:"b"})})),h=i&&"toString"!=l.name;(c||h)&&r(RegExp.prototype,"toString",(function(){var t=a(this);return"/"+s(t.source)+"/"+s(u(t))}),{unsafe:!0})},380:function(t,e,n){},381:function(t,e,n){},382:function(t,e,n){},383:function(t,e,n){},384:function(t,e,n){},385:function(t,e,n){},386:function(t,e){t.exports=function(t){return null==t}},387:function(t,e,n){},388:function(t,e,n){},389:function(t,e,n){},390:function(t,e,n){},391:function(t,e,n){},392:function(t,e,n){},401:function(t,e,n){"use strict";n.r(e);n(125),n(9);var i=n(367),r={name:"SidebarGroup",components:{DropdownTransition:n(402).a},props:["item","open","collapsable","depth"],beforeCreate:function(){this.$options.components.SidebarLinks=n(401).default},methods:{isActive:i.e}},a=(n(421),n(65)),s=Object(a.a)(r,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("section",{staticClass:"sidebar-group",class:[{collapsable:t.collapsable,"is-sub-group":0!==t.depth},"depth-"+t.depth]},[t.item.path?n("RouterLink",{staticClass:"sidebar-heading clickable",class:{open:t.open,active:t.isActive(t.$route,t.item.path)},attrs:{to:t.item.path},nativeOn:{click:function(e){return t.$emit("toggle")}}},[n("span",[t._v(t._s(t.item.title))]),t._v(" "),t.collapsable?n("span",{staticClass:"arrow",class:t.open?"down":"right"}):t._e()]):n("p",{staticClass:"sidebar-heading",class:{open:t.open},on:{click:function(e){return t.$emit("toggle")}}},[n("span",[t._v(t._s(t.item.title))]),t._v(" "),t.collapsable?n("span",{staticClass:"arrow",class:t.open?"down":"right"}):t._e()]),t._v(" "),n("DropdownTransition",[t.open||!t.collapsable?n("SidebarLinks",{staticClass:"sidebar-group-items",attrs:{items:t.item.children,"sidebar-depth":t.item.sidebarDepth,"initial-open-group-index":t.item.initialOpenGroupIndex,depth:t.depth+1}}):t._e()],1)],1)}),[],!1,null,null,null).exports;n(422),n(32),n(124),n(93);function o(t,e,n,i,r){var a={props:{to:e,activeClass:"",exactActiveClass:""},class:{active:i,"sidebar-link":!0}};return r>2&&(a.style={"padding-left":r+"rem"}),t("RouterLink",a,n)}function u(t,e,n,r,a){var s=arguments.length>5&&void 0!==arguments[5]?arguments[5]:1;return!e||s>a?null:t("ul",{class:"sidebar-sub-headers"},e.map((function(e){var l=Object(i.e)(r,n+"#"+e.slug);return t("li",{class:"sidebar-sub-header"},[o(t,n+"#"+e.slug,e.title,l,e.level-1),u(t,e.children,n,r,a,s+1)])})))}var l={functional:!0,props:["item","sidebarDepth"],render:function(t,e){var n=e.parent,r=n.$page,a=(n.$site,n.$route),s=n.$themeConfig,l=n.$themeLocaleConfig,c=e.props,h=c.item,f=c.sidebarDepth,p=Object(i.e)(a,h.path),d="auto"===h.type?p||h.children.some((function(t){return Object(i.e)(a,h.basePath+"#"+t.slug)})):p,g="external"===h.type?function(t,e,n){return t("a",{attrs:{href:e,target:"_blank",rel:"noopener noreferrer"},class:{"sidebar-link":!0}},[n,t("OutboundLink")])}(t,h.path,h.title||h.path):o(t,h.path,h.title||h.path,d),v=[r.frontmatter.sidebarDepth,f,l.sidebarDepth,s.sidebarDepth,1].find((function(t){return void 0!==t})),m=l.displayAllHeaders||s.displayAllHeaders;return"auto"===h.type?[g,u(t,h.children,h.basePath,a,v)]:(d||m)&&h.headers&&!i.d.test(h.path)?[g,u(t,Object(i.c)(h.headers),h.path,a,v)]:g}};n(423);function c(t,e){if("group"===e.type){var n=e.path&&Object(i.e)(t,e.path),r=e.children.some((function(e){return"group"===e.type?c(t,e):"page"===e.type&&Object(i.e)(t,e.path)}));return n||r}return!1}var h={name:"SidebarLinks",components:{SidebarGroup:s,SidebarLink:Object(a.a)(l,void 0,void 0,!1,null,null,null).exports},props:["items","depth","sidebarDepth","initialOpenGroupIndex"],data:function(){return{openGroupIndex:this.initialOpenGroupIndex||0}},watch:{$route:function(){this.refreshIndex()}},created:function(){this.refreshIndex()},methods:{refreshIndex:function(){var t=function(t,e){for(var n=0;n-1&&(this.openGroupIndex=t)},toggleGroup:function(t){this.openGroupIndex=t===this.openGroupIndex?-1:t},isActive:function(t){return Object(i.e)(this.$route,t.regularPath)}}},f=Object(a.a)(h,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return t.items.length?n("ul",{staticClass:"sidebar-links"},t._l(t.items,(function(e,i){return n("li",{key:i},["group"===e.type?n("SidebarGroup",{attrs:{item:e,open:i===t.openGroupIndex,collapsable:e.collapsable||e.collapsible,depth:t.depth},on:{toggle:function(e){return t.toggleGroup(i)}}}):n("SidebarLink",{attrs:{"sidebar-depth":t.sidebarDepth,item:e}})],1)})),0):t._e()}),[],!1,null,null,null);e.default=f.exports},402:function(t,e,n){"use strict";var i={name:"DropdownTransition",methods:{setHeight:function(t){t.style.height=t.scrollHeight+"px"},unsetHeight:function(t){t.style.height=""}}},r=(n(413),n(65)),a=Object(r.a)(i,(function(){var t=this.$createElement;return(this._self._c||t)("transition",{attrs:{name:"dropdown"},on:{enter:this.setHeight,"after-enter":this.unsetHeight,"before-leave":this.setHeight}},[this._t("default")],2)}),[],!1,null,null,null);e.a=a.exports},403:function(t,e,n){"use strict";var i=n(1),r=n(404);i({target:"String",proto:!0,forced:n(405)("link")},{link:function(t){return r(this,"a","href",t)}})},404:function(t,e,n){var i=n(3),r=n(33),a=n(17),s=/"/g,o=i("".replace);t.exports=function(t,e,n,i){var u=a(r(t)),l="<"+e;return""!==n&&(l+=" "+n+'="'+o(a(i),s,""")+'"'),l+">"+u+""}},405:function(t,e,n){var i=n(2);t.exports=function(t){return i((function(){var e=""[t]('"');return e!==e.toLowerCase()||e.split('"').length>3}))}},406:function(t,e,n){"use strict";n(371)},407:function(t,e,n){var i=n(1),r=n(408);i({global:!0,forced:parseInt!=r},{parseInt:r})},408:function(t,e,n){var i=n(0),r=n(2),a=n(3),s=n(17),o=n(372).trim,u=n(369),l=i.parseInt,c=i.Symbol,h=c&&c.iterator,f=/^[+-]?0x/i,p=a(f.exec),d=8!==l(u+"08")||22!==l(u+"0x16")||h&&!r((function(){l(Object(h))}));t.exports=d?function(t,e){var n=o(s(t));return l(n,e>>>0||(p(f,n)?16:10))}:l},409:function(t,e,n){var i=n(98).PROPER,r=n(2),a=n(369);t.exports=function(t){return r((function(){return!!a[t]()||"​…᠎"!=="​…᠎"[t]()||i&&a[t].name!==t}))}},410:function(t,e,n){"use strict";var i,r=n(1),a=n(3),s=n(36).f,o=n(95),u=n(17),l=n(131),c=n(33),h=n(132),f=n(14),p=a("".endsWith),d=a("".slice),g=Math.min,v=h("endsWith");r({target:"String",proto:!0,forced:!!(f||v||(i=s(String.prototype,"endsWith"),!i||i.writable))&&!v},{endsWith:function(t){var e=u(c(this));l(t);var n=arguments.length>1?arguments[1]:void 0,i=e.length,r=void 0===n?i:g(o(n),i),a=u(t);return p?p(e,a,r):d(e,r-a.length,r)===a}})},411:function(t,e,n){"use strict";n(380)},412:function(t,e,n){"use strict";n(381)},413:function(t,e,n){"use strict";n(382)},414:function(t,e,n){"use strict";n(383)},415:function(t,e,n){"use strict";n(384)},416:function(t,e,n){"use strict";n(385)},417:function(t,e,n){"use strict";n(387)},418:function(t,e,n){var i=n(46),r=n(21),a=n(37);t.exports=function(t){return"string"==typeof t||!r(t)&&a(t)&&"[object String]"==i(t)}},419:function(t,e,n){"use strict";n(388)},420:function(t,e,n){"use strict";n(389)},421:function(t,e,n){"use strict";n(390)},422:function(t,e,n){"use strict";var i=n(1),r=n(45).find,a=n(128),s=!0;"find"in[]&&Array(1).find((function(){s=!1})),i({target:"Array",proto:!0,forced:s},{find:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}}),a("find")},423:function(t,e,n){"use strict";n(391)},424:function(t,e,n){"use strict";n(392)},491:function(t,e,n){"use strict";n.r(e);n(403),n(125),n(9),n(126);var i=n(367),r={name:"NavLink",props:{item:{required:!0}},computed:{link:function(){return Object(i.b)(this.item.link)},exact:function(){var t=this;return this.$site.locales?Object.keys(this.$site.locales).some((function(e){return e===t.link})):"/"===this.link},isNonHttpURI:function(){return Object(i.g)(this.link)||Object(i.h)(this.link)},isBlankTarget:function(){return"_blank"===this.target},isInternal:function(){return!Object(i.f)(this.link)&&!this.isBlankTarget},target:function(){return this.isNonHttpURI?null:this.item.target?this.item.target:Object(i.f)(this.link)?"_blank":""},rel:function(){return this.isNonHttpURI||!1===this.item.rel?null:this.item.rel?this.item.rel:this.isBlankTarget?"noopener noreferrer":null}},methods:{focusoutAction:function(){this.$emit("focusout")}}},a=n(65),s=Object(a.a)(r,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return t.isInternal?n("RouterLink",{staticClass:"nav-link",attrs:{to:t.link,exact:t.exact},nativeOn:{focusout:function(e){return t.focusoutAction.apply(null,arguments)}}},[t._v("\n "+t._s(t.item.text)+"\n")]):n("a",{staticClass:"nav-link external",attrs:{href:t.link,target:t.target,rel:t.rel},on:{focusout:t.focusoutAction}},[t._v("\n "+t._s(t.item.text)+"\n "),t.isBlankTarget?n("OutboundLink"):t._e()],1)}),[],!1,null,null,null).exports,o={name:"Home",components:{NavLink:s},computed:{data:function(){return this.$page.frontmatter},actionLink:function(){return{link:this.data.actionLink,text:this.data.actionText}}}},u=(n(406),Object(a.a)(o,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("main",{staticClass:"home",attrs:{"aria-labelledby":null!==t.data.heroText?"main-title":null}},[n("header",{staticClass:"hero"},[t.data.heroImage?n("img",{attrs:{src:t.$withBase(t.data.heroImage),alt:t.data.heroAlt||"hero"}}):t._e(),t._v(" "),null!==t.data.heroText?n("h1",{attrs:{id:"main-title"}},[t._v("\n "+t._s(t.data.heroText||t.$title||"Hello")+"\n ")]):t._e(),t._v(" "),null!==t.data.tagline?n("p",{staticClass:"description"},[t._v("\n "+t._s(t.data.tagline||t.$description||"Welcome to your VuePress site")+"\n ")]):t._e(),t._v(" "),t.data.actionText&&t.data.actionLink?n("p",{staticClass:"action"},[n("NavLink",{staticClass:"action-button",attrs:{item:t.actionLink}})],1):t._e()]),t._v(" "),t.data.features&&t.data.features.length?n("div",{staticClass:"features"},t._l(t.data.features,(function(e,i){return n("div",{key:i,staticClass:"feature"},[n("h2",[t._v(t._s(e.title))]),t._v(" "),n("p",[t._v(t._s(e.details))])])})),0):t._e(),t._v(" "),n("Content",{staticClass:"theme-default-content custom"}),t._v(" "),t.data.footer?n("div",{staticClass:"footer"},[t._v("\n "+t._s(t.data.footer)+"\n ")]):n("Content",{staticClass:"footer",attrs:{"slot-key":"footer"}})],1)}),[],!1,null,null,null).exports),l=(n(407),n(373),n(195),n(127),n(43),n(32),n(368),n(210),n(211),n(201),n(94),n(374),n(376),n(378),n(379),n(93),n(370),n(124),n(410),n(213)),c=n.n(l),h=function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,i=c()(e,"title","");return c()(e,"frontmatter.tags")&&(i+=" ".concat(e.frontmatter.tags.join(" "))),n&&(i+=" ".concat(n)),f(t,i)},f=function(t,e){var n=function(t){return t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")},i=new RegExp("[^\0-]"),r=t.split(/\s+/g).map((function(t){return t.trim()})).filter((function(t){return!!t}));if(i.test(t))return r.some((function(t){return e.toLowerCase().indexOf(t)>-1}));var a=t.endsWith(" ");return new RegExp(r.map((function(t,e){return r.length!==e+1||a?"(?=.*\\b".concat(n(t),"\\b)"):"(?=.*\\b".concat(n(t),")")})).join("")+".+","gi").test(e)},p={name:"SearchBox",data:function(){return{query:"",focused:!1,focusIndex:0,placeholder:void 0}},computed:{showSuggestions:function(){return this.focused&&this.suggestions&&this.suggestions.length},suggestions:function(){var t=this.query.trim().toLowerCase();if(t){for(var e=this.$site.pages,n=this.$site.themeConfig.searchMaxSuggestions||5,i=this.$localePath,r=[],a=0;a=n);a++){var s=e[a];if(this.getPageLocalePath(s)===i&&this.isSearchable(s))if(h(t,s))r.push(s);else if(s.headers)for(var o=0;o=n);o++){var u=s.headers[o];u.title&&h(t,s,u.title)&&r.push(Object.assign({},s,{path:s.path+"#"+u.slug,header:u}))}}return r}},alignRight:function(){return(this.$site.themeConfig.nav||[]).length+(this.$site.repo?1:0)<=2}},mounted:function(){this.placeholder=this.$site.themeConfig.searchPlaceholder||"",document.addEventListener("keydown",this.onHotkey)},beforeDestroy:function(){document.removeEventListener("keydown",this.onHotkey)},methods:{getPageLocalePath:function(t){for(var e in this.$site.locales||{})if("/"!==e&&0===t.path.indexOf(e))return e;return"/"},isSearchable:function(t){var e=null;return null===e||(e=Array.isArray(e)?e:new Array(e)).filter((function(e){return t.path.match(e)})).length>0},onHotkey:function(t){t.srcElement===document.body&&["s","/"].includes(t.key)&&(this.$refs.input.focus(),t.preventDefault())},onUp:function(){this.showSuggestions&&(this.focusIndex>0?this.focusIndex--:this.focusIndex=this.suggestions.length-1)},onDown:function(){this.showSuggestions&&(this.focusIndex "+t._s(e.header.title))]):t._e()])])})),0):t._e()])}),[],!1,null,null,null).exports),g=(n(412),Object(a.a)({},(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"sidebar-button",on:{click:function(e){return t.$emit("toggle-sidebar")}}},[n("svg",{staticClass:"icon",attrs:{xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",role:"img",viewBox:"0 0 448 512"}},[n("path",{attrs:{fill:"currentColor",d:"M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"}})])])}),[],!1,null,null,null).exports),v=n(63),m=(n(212),n(402)),b=n(214),k=n.n(b),_={name:"DropdownLink",components:{NavLink:s,DropdownTransition:m.a},props:{item:{required:!0}},data:function(){return{open:!1}},computed:{dropdownAriaLabel:function(){return this.item.ariaLabel||this.item.text}},watch:{$route:function(){this.open=!1}},methods:{setOpen:function(t){this.open=t},isLastItemOfArray:function(t,e){return k()(e)===t},handleDropdown:function(){0===event.detail&&this.setOpen(!this.open)}}},x=(n(414),{name:"NavLinks",components:{NavLink:s,DropdownLink:Object(a.a)(_,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"dropdown-wrapper",class:{open:t.open}},[n("button",{staticClass:"dropdown-title",attrs:{type:"button","aria-label":t.dropdownAriaLabel},on:{click:t.handleDropdown}},[n("span",{staticClass:"title"},[t._v(t._s(t.item.text))]),t._v(" "),n("span",{staticClass:"arrow down"})]),t._v(" "),n("button",{staticClass:"mobile-dropdown-title",attrs:{type:"button","aria-label":t.dropdownAriaLabel},on:{click:function(e){return t.setOpen(!t.open)}}},[n("span",{staticClass:"title"},[t._v(t._s(t.item.text))]),t._v(" "),n("span",{staticClass:"arrow",class:t.open?"down":"right"})]),t._v(" "),n("DropdownTransition",[n("ul",{directives:[{name:"show",rawName:"v-show",value:t.open,expression:"open"}],staticClass:"nav-dropdown"},t._l(t.item.items,(function(e,i){return n("li",{key:e.link||i,staticClass:"dropdown-item"},["links"===e.type?n("h4",[t._v("\n "+t._s(e.text)+"\n ")]):t._e(),t._v(" "),"links"===e.type?n("ul",{staticClass:"dropdown-subitem-wrapper"},t._l(e.items,(function(i){return n("li",{key:i.link,staticClass:"dropdown-subitem"},[n("NavLink",{attrs:{item:i},on:{focusout:function(n){t.isLastItemOfArray(i,e.items)&&t.isLastItemOfArray(e,t.item.items)&&t.setOpen(!1)}}})],1)})),0):n("NavLink",{attrs:{item:e},on:{focusout:function(n){t.isLastItemOfArray(e,t.item.items)&&t.setOpen(!1)}}})],1)})),0)])],1)}),[],!1,null,null,null).exports},computed:{userNav:function(){return this.$themeLocaleConfig.nav||this.$site.themeConfig.nav||[]},nav:function(){var t=this,e=this.$site.locales;if(e&&Object.keys(e).length>1){var n=this.$page.path,i=this.$router.options.routes,r=this.$site.themeConfig.locales||{},a={text:this.$themeLocaleConfig.selectText||"Languages",ariaLabel:this.$themeLocaleConfig.ariaLabel||"Select language",items:Object.keys(e).map((function(a){var s,o=e[a],u=r[a]&&r[a].label||o.lang;return o.lang===t.$lang?s=n:(s=n.replace(t.$localeConfig.path,a),i.some((function(t){return t.path===s}))||(s=a)),{text:u,link:s}}))};return[].concat(Object(v.a)(this.userNav),[a])}return this.userNav},userLinks:function(){return(this.nav||[]).map((function(t){return Object.assign(Object(i.j)(t),{items:(t.items||[]).map(i.j)})}))},repoLink:function(){var t=this.$site.themeConfig.repo;return t?/^https?:/.test(t)?t:"https://github.com/".concat(t):null},repoLabel:function(){if(this.repoLink){if(this.$site.themeConfig.repoLabel)return this.$site.themeConfig.repoLabel;for(var t=this.repoLink.match(/^https?:\/\/[^/]+/)[0],e=["GitHub","GitLab","Bitbucket"],n=0;nMath.abs(n)&&Math.abs(e)>40&&(e>0&&this.touchStart.x<=80?this.toggleSidebar(!0):this.toggleSidebar(!1))}}}),G=Object(a.a)(W,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"theme-container",class:t.pageClasses,on:{touchstart:t.onTouchStart,touchend:t.onTouchEnd}},[t.shouldShowNavbar?n("Navbar",{on:{"toggle-sidebar":t.toggleSidebar}}):t._e(),t._v(" "),n("div",{staticClass:"sidebar-mask",on:{click:function(e){return t.toggleSidebar(!1)}}}),t._v(" "),n("Sidebar",{attrs:{items:t.sidebarItems},on:{"toggle-sidebar":t.toggleSidebar},scopedSlots:t._u([{key:"top",fn:function(){return[t._t("sidebar-top")]},proxy:!0},{key:"bottom",fn:function(){return[t._t("sidebar-bottom")]},proxy:!0}],null,!0)}),t._v(" "),t.$page.frontmatter.home?n("Home"):n("Page",{attrs:{"sidebar-items":t.sidebarItems},scopedSlots:t._u([{key:"top",fn:function(){return[t._t("page-top")]},proxy:!0},{key:"bottom",fn:function(){return[t._t("page-bottom")]},proxy:!0}],null,!0)})],1)}),[],!1,null,null,null);e.default=G.exports}}]); \ No newline at end of file diff --git a/book/assets/js/20.a09340aa.js b/book/assets/js/20.a09340aa.js new file mode 100644 index 000000000..ae2714d68 --- /dev/null +++ b/book/assets/js/20.a09340aa.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[20],{492:function(t,e,s){"use strict";s.r(e);var n=["There's nothing here.","How did we get here?","That's a Four-Oh-Four.","Looks like we've got some broken links."],o={methods:{getMsg:function(){return n[Math.floor(Math.random()*n.length)]}}},i=s(65),h=Object(i.a)(o,(function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"theme-container"},[e("div",{staticClass:"theme-default-content"},[e("h1",[this._v("404")]),this._v(" "),e("blockquote",[this._v(this._s(this.getMsg()))]),this._v(" "),e("RouterLink",{attrs:{to:"/"}},[this._v("\n Take me home.\n ")])],1)])}),[],!1,null,null,null);e.default=h.exports}}]); \ No newline at end of file diff --git a/book/assets/js/21.e1602f70.js b/book/assets/js/21.e1602f70.js new file mode 100644 index 000000000..e01ba110e --- /dev/null +++ b/book/assets/js/21.e1602f70.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{499:function(e,t,r){"use strict";r.r(t);var a=r(65),n=Object(a.a)({},(function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("h1",{attrs:{id:"about"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#about"}},[e._v("#")]),e._v(" About")]),e._v(" "),r("h2",{attrs:{id:"maintainers"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#maintainers"}},[e._v("#")]),e._v(" Maintainers")]),e._v(" "),r("p",[r("strong",[e._v("Alexander Bainczyk")]),e._v(" "),r("br"),e._v(" "),r("a",{attrs:{href:"mailto:alexander.bainczyk@tu-dortmund.de"}},[e._v("alexander.bainczyk@tu-dortmund.de")])]),e._v(" "),r("p",[r("strong",[e._v("Marco Krumrey")]),e._v(" "),r("br"),e._v(" "),r("a",{attrs:{href:"mailto:marco.krumrey@tu-dortmund.de"}},[e._v("marco.krumrey@tu-dortmund.de")])]),e._v(" "),r("h2",{attrs:{id:"copyright"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#copyright"}},[e._v("#")]),e._v(" Copyright")]),e._v(" "),r("p",[e._v("This project is open source and licensed under the "),r("a",{attrs:{href:"https://www.apache.org/licenses/LICENSE-2.0",target:"_blank",rel:"noopener noreferrer"}},[e._v("Apache-2 license"),r("OutboundLink")],1),e._v(".")]),e._v(" "),r("p",[e._v("Copyright 2015 - 2022 TU Dortmund")]),e._v(" "),r("h2",{attrs:{id:"issue-management"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#issue-management"}},[e._v("#")]),e._v(" Issue management")]),e._v(" "),r("p",[e._v("We use GitHub for the issue and project management.\nIf you find a bug in the software, inaccuracies in this documentation or have other suggestions, please file an issue "),r("a",{attrs:{href:"https://github.com/LearnLib/alex/issues",target:"_blank",rel:"noopener noreferrer"}},[e._v("here"),r("OutboundLink")],1),e._v(" or submit a pull request.")])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/book/assets/js/22.0c93c711.js b/book/assets/js/22.0c93c711.js new file mode 100644 index 000000000..9f5216e6d --- /dev/null +++ b/book/assets/js/22.0c93c711.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{500:function(e,a,t){"use strict";t.r(a);var l=t(65),r=Object(l.a)({},(function(){var e=this,a=e.$createElement,t=e._self._c||a;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"alex-cli"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#alex-cli"}},[e._v("#")]),e._v(" ALEX CLI")]),e._v(" "),t("p",[e._v("There is a "),t("em",[e._v("Command Line Interface")]),e._v(" (CLI) available for starting tests and learning processes in ALEX via the command line.")]),e._v(" "),t("h2",{attrs:{id:"installation"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[e._v("#")]),e._v(" Installation")]),e._v(" "),t("h3",{attrs:{id:"npm-package"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#npm-package"}},[e._v("#")]),e._v(" NPM package")]),e._v(" "),t("p",[e._v("The CLI is available as a NodeJS module "),t("em",[e._v("alex-cli")]),e._v(" and can be installed with")]),e._v(" "),t("p",[t("code",[e._v("npm install -g alex-cli")])]),e._v(" "),t("h3",{attrs:{id:"docker-image"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#docker-image"}},[e._v("#")]),e._v(" Docker image")]),e._v(" "),t("ol",[t("li",[t("p",[e._v("The CLI is available as a Docker image and can be installed with")]),e._v(" "),t("p",[t("code",[e._v("docker pull ghcr.io/learnlib/alex/alex-cli:3.0.0")])])]),e._v(" "),t("li",[t("p",[e._v("Run the docker image and execute CLI commands:")]),e._v(" "),t("p",[t("code",[e._v("docker run alex/alex-cli alex-cli [...]")])])])]),e._v(" "),t("h2",{attrs:{id:"usage"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#usage"}},[e._v("#")]),e._v(" Usage")]),e._v(" "),t("ul",[t("li",[e._v("Execute "),t("code",[e._v("alex-cli --help")]),e._v(" to get all available parameters.")]),e._v(" "),t("li",[e._v("The readme can be found "),t("a",{attrs:{href:"https://github.com/LearnLib/alex/tree/main/cli",target:"_blank",rel:"noopener noreferrer"}},[e._v("here"),t("OutboundLink")],1),e._v(".")])]),e._v(" "),t("h2",{attrs:{id:"examples"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#examples"}},[e._v("#")]),e._v(" Examples")]),e._v(" "),t("ul",[t("li",[e._v("For usage examples, look at the "),t("a",{attrs:{href:"https://github.com/LearnLib/alex/tree/main/cli/examples",target:"_blank",rel:"noopener noreferrer"}},[e._v("examples directory"),t("OutboundLink")],1),e._v(" in the repository.")])])])}),[],!1,null,null,null);a.default=r.exports}}]); \ No newline at end of file diff --git a/book/assets/js/23.aca9cbd9.js b/book/assets/js/23.aca9cbd9.js new file mode 100644 index 000000000..8f5eb05bd --- /dev/null +++ b/book/assets/js/23.aca9cbd9.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{501:function(s,t,a){"use strict";a.r(t);var n=a(65),e=Object(n.a)({},(function(){var s=this,t=s.$createElement,a=s._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[a("h1",{attrs:{id:"alex-as-dependency"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#alex-as-dependency"}},[s._v("#")]),s._v(" ALEX as dependency")]),s._v(" "),a("p",[s._v("You can use the "),a("code",[s._v("backend")]),s._v(" module of ALEX as a dependency in other Maven projects.")]),s._v(" "),a("ol",[a("li",[a("p",[s._v("Add the sonatype snapshot repository to your "),a("code",[s._v("pom.xml")]),s._v(":")]),s._v(" "),a("div",{staticClass:"language-xml line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-xml"}},[a("code",[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("repositories")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("\x3c!-- other repositories --\x3e")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("repository")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("id")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("sonatype-nexus-snapshots"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("name")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("Sonatype Nexus Snapshots"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("url")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("https://oss.sonatype.org/content/repositories/snapshots"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br")])])]),s._v(" "),a("li",[a("p",[s._v("Add ALEX as Maven dependency in your "),a("code",[s._v("pom.xml")]),s._v(":")]),s._v(" "),a("div",{staticClass:"language-xml line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-xml"}},[a("code",[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("dependencies")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("\x3c!-- other dependencies --\x3e")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("dependency")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("groupId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("de.learnlib.alex"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("artifactId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("alex-backend"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("version")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("3.0.0"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br")])]),a("p",[s._v("If you are using a "),a("strong",[s._v("Spring-Boot")]),s._v(" app, exclude all related dependencies from the ALEX dependency:")]),s._v(" "),a("div",{staticClass:"language-xml line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-xml"}},[a("code",[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("dependencies")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("\x3c!-- other dependencies --\x3e")]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("dependency")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("groupId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("de.learnlib.alex"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("artifactId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("alex-backend"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("version")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("3.0.0"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[s._v("\x3c!-- exclude dependencies from Spring-Boot if you are using ALEX within another Spring-Boot app --\x3e")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("exclusions")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("exclusion")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("groupId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("org.springframework.boot"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("<")]),s._v("artifactId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(">")])]),s._v("*"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token tag"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("")])]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br"),a("span",{staticClass:"line-number"},[s._v("7")]),a("br"),a("span",{staticClass:"line-number"},[s._v("8")]),a("br"),a("span",{staticClass:"line-number"},[s._v("9")]),a("br"),a("span",{staticClass:"line-number"},[s._v("10")]),a("br"),a("span",{staticClass:"line-number"},[s._v("11")]),a("br"),a("span",{staticClass:"line-number"},[s._v("12")]),a("br"),a("span",{staticClass:"line-number"},[s._v("13")]),a("br"),a("span",{staticClass:"line-number"},[s._v("14")]),a("br"),a("span",{staticClass:"line-number"},[s._v("15")]),a("br"),a("span",{staticClass:"line-number"},[s._v("16")]),a("br"),a("span",{staticClass:"line-number"},[s._v("17")]),a("br")])])])])])}),[],!1,null,null,null);t.default=e.exports}}]); \ No newline at end of file diff --git a/book/assets/js/24.b98f7483.js b/book/assets/js/24.b98f7483.js new file mode 100644 index 000000000..5b26d967a --- /dev/null +++ b/book/assets/js/24.b98f7483.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{503:function(e,t,a){"use strict";a.r(t);var s=a(65),r=Object(s.a)({},(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[a("h1",{attrs:{id:"development-kubernetes"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#development-kubernetes"}},[e._v("#")]),e._v(" Development (Kubernetes)")]),e._v(" "),a("h2",{attrs:{id:"local-setup"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#local-setup"}},[e._v("#")]),e._v(" Local setup")]),e._v(" "),a("p",[e._v("This section describes the steps that are required to deploy and run ALEX on a local kubernetes cluster.")]),e._v(" "),a("h3",{attrs:{id:"prerequisites"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#prerequisites"}},[e._v("#")]),e._v(" Prerequisites")]),e._v(" "),a("ol",[a("li",[e._v("Install "),a("a",{attrs:{href:"Docker"}},[e._v("docker")]),e._v(", "),a("a",{attrs:{href:"Minikube"}},[e._v("minikube")]),e._v(", "),a("a",{attrs:{href:"Kubectl"}},[e._v("kubectl")]),e._v(", "),a("a",{attrs:{href:"Helm"}},[e._v("helm")]),e._v(" and "),a("a",{attrs:{href:"Skaffold"}},[e._v("skaffold")]),e._v(".")]),e._v(" "),a("li",[e._v("Start minikube: "),a("code",[e._v("minikube start")]),e._v(".")]),e._v(" "),a("li",[e._v("Install necessary add-ons:"),a("div",{staticClass:"language- line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("minikube addons enable ingress && \\\nminikube addons enable ingress-dns\n")])]),e._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[e._v("1")]),a("br"),a("span",{staticClass:"line-number"},[e._v("2")]),a("br")])])]),e._v(" "),a("li",[e._v("Add a host alias to the "),a("code",[e._v("/etc/hosts")]),e._v(" file:\nExecute "),a("code",[e._v("minikube ip")]),e._v(" to get the IP address of the local cluster and add an entry "),a("code",[e._v(" alex")]),e._v(" to the "),a("code",[e._v("/etc/hosts")]),e._v(" file.")]),e._v(" "),a("li",[e._v("Install secret: "),a("code",[e._v("kubectl apply -f infrastructure/helm-chart/secrets-local.yaml")])]),e._v(" "),a("li",[e._v("Install Keda:\n"),a("ol",[a("li",[a("code",[e._v("helm repo add kedacore https://kedacore.github.io/charts && helm repo update")])]),e._v(" "),a("li",[a("code",[e._v("kubectl create namespace keda")])]),e._v(" "),a("li",[a("code",[e._v("helm install keda kedacore/keda --namespace keda")])])])])]),e._v(" "),a("h3",{attrs:{id:"deploy-alex-to-minikube"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#deploy-alex-to-minikube"}},[e._v("#")]),e._v(" Deploy ALEX to Minikube")]),e._v(" "),a("ol",[a("li",[e._v("Ensure you use the local minikube kubernetes context: "),a("code",[e._v("kubectl config use-context minikube")])]),e._v(" "),a("li",[e._v("In the root of the repository, run "),a("code",[e._v("skaffold dev -p local")]),e._v(" to execute the deployment.")]),e._v(" "),a("li",[e._v("Open "),a("code",[e._v("http://alex/")]),e._v(" in a Web browser.")])]),e._v(" "),a("h2",{attrs:{id:"remote-setup"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#remote-setup"}},[e._v("#")]),e._v(" Remote setup")]),e._v(" "),a("p",[e._v("This section describes the steps that are required to deploy and run ALEX on a remote kubernetes cluster.")]),e._v(" "),a("h3",{attrs:{id:"prerequisites-2"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#prerequisites-2"}},[e._v("#")]),e._v(" Prerequisites")]),e._v(" "),a("ol",[a("li",[e._v("Install "),a("a",{attrs:{href:"microk8s"}},[e._v("microk8s")]),e._v(" on a server.")]),e._v(" "),a("li",[e._v("Enable the following add-ons: "),a("code",[e._v("microk8s enable dns ingress registry storage")]),e._v(".")]),e._v(" "),a("li",[e._v("Copy the cluster details from "),a("code",[e._v("microk8s kubectl config view")]),e._v(" to the local "),a("code",[e._v("/.kube/config")]),e._v(" file.")])]),e._v(" "),a("h3",{attrs:{id:"deploy-alex-to-a-remote-cluster"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#deploy-alex-to-a-remote-cluster"}},[e._v("#")]),e._v(" Deploy ALEX to a remote cluster")]),e._v(" "),a("ol",[a("li",[e._v("Create a file "),a("code",[e._v("./helm-chart/values-temp.yaml")]),e._v(", and set the necessary properties (see "),a("code",[e._v("values-local.yaml")]),e._v(").")]),e._v(" "),a("li",[e._v("Switch to the kubernetes context of the cluster that you have entered earlier: "),a("code",[e._v("kubectl config use-context ")]),e._v(".")]),e._v(" "),a("li",[e._v("In the root of the repository, execute "),a("code",[e._v("skaffold run -p temp")]),e._v(" to deploy the app.")])])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/book/assets/js/25.301b9aac.js b/book/assets/js/25.301b9aac.js new file mode 100644 index 000000000..fad944322 --- /dev/null +++ b/book/assets/js/25.301b9aac.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[25],{504:function(e,n,r){"use strict";r.r(n);var t=r(65),o=Object(t.a)({},(function(){var e=this,n=e.$createElement,r=e._self._c||n;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("h1",{attrs:{id:"performing-a-release"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#performing-a-release"}},[e._v("#")]),e._v(" Performing a release")]),e._v(" "),r("p",[e._v("In the "),r("code",[e._v("developer")]),e._v(" branch, perform the following steps:")]),e._v(" "),r("ol",[r("li",[e._v("Update the version, in the following files:\n"),r("ul",[r("li",[r("code",[e._v("backend/pom.xml")])]),e._v(" "),r("li",[r("code",[e._v("frontend/package.json")])]),e._v(" "),r("li",[r("code",[e._v("frontend/src/environments/environment.*.ts")])]),e._v(" "),r("li",[r("code",[e._v("cli/package.json")])]),e._v(" "),r("li",[r("code",[e._v("docs/package.json")])])])]),e._v(" "),r("li",[e._v("Commit and push the changes to the "),r("code",[e._v("developer")]),e._v(" branch.\n"),r("ul",[r("li",[e._v("Ensure that the "),r("a",{attrs:{href:"https://github.com/LearnLib/alex/actions",target:"_blank",rel:"noopener noreferrer"}},[e._v("CI pipeline"),r("OutboundLink")],1),e._v(" passes.")])])]),e._v(" "),r("li",[e._v("Merge the "),r("code",[e._v("developer")]),e._v(" branch in the "),r("code",[e._v("master")]),e._v(" branch.\n"),r("ul",[r("li",[e._v("Ensure that the "),r("a",{attrs:{href:"https://github.com/LearnLib/alex/actions",target:"_blank",rel:"noopener noreferrer"}},[e._v("CI pipeline"),r("OutboundLink")],1),e._v(" passes.")])])]),e._v(" "),r("li",[e._v("In the "),r("code",[e._v("master")]),e._v(" branch, create a new tag with the new version and perform a GitHub release.\n"),r("ul",[r("li",[e._v("Append the current "),r("code",[e._v("docker-compose.production.yml")]),e._v(" file.\nFor this purpose, rename the file according to the current release version, e.g. "),r("code",[e._v("docker-compose.alex-3.0.0.yml")])])])]),e._v(" "),r("li",[e._v("In the "),r("code",[e._v("developer")]),e._v(" branch, increment the version in all files from step 1 to the next minor version and append the "),r("em",[e._v("-SNAPSHOT")]),e._v(" suffix.")])])])}),[],!1,null,null,null);n.default=o.exports}}]); \ No newline at end of file diff --git a/book/assets/js/26.70b7df70.js b/book/assets/js/26.70b7df70.js new file mode 100644 index 000000000..0a6d984dd --- /dev/null +++ b/book/assets/js/26.70b7df70.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[26],{505:function(s,t,a){"use strict";a.r(t);var e=a(65),n=Object(e.a)({},(function(){var s=this,t=s.$createElement,a=s._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[a("h1",{attrs:{id:"rest-api"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#rest-api"}},[s._v("#")]),s._v(" REST API")]),s._v(" "),a("h2",{attrs:{id:"authentication"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#authentication"}},[s._v("#")]),s._v(" Authentication")]),s._v(" "),a("p",[s._v("The REST API of ALEX supports authentication via "),a("a",{attrs:{href:"http://jwt.io/",target:"_blank",rel:"noopener noreferrer"}},[s._v("JSON Web Tokens (JWT)"),a("OutboundLink")],1),s._v(".")]),s._v(" "),a("ol",[a("li",[a("p",[s._v("Make a "),a("code",[s._v("POST")]),s._v(" request to "),a("code",[s._v("/rest/users/login")]),s._v(" with a HTTP body that contains a serialized user object which looks like:")]),s._v(" "),a("div",{staticClass:"language-JSON line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-json"}},[a("code",[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[s._v('"email"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[s._v('"password"')]),s._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br")])])]),s._v(" "),a("li",[a("p",[s._v("You should receive a base64 encoded JWT in a JSON object "),a("code",[s._v('{"token": "THEBASE64ENCODEDTOKEN"}')]),s._v(".\nSave it and send it with each HTTP request to the API in the HTTP-Authorization header as follows: "),a("code",[s._v("Authorization: Bearer THEBASE64ENCODEDTOKEN")]),s._v(".")])])]),s._v(" "),a("p",[s._v("The token provides information about the user as a base64 encoded JSON object as payload.\nThe payload looks like:")]),s._v(" "),a("div",{staticClass:"language-JSON line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-json"}},[a("code",[a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("{")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[s._v('"email"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[s._v('"username"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" \n "),a("span",{pre:!0,attrs:{class:"token property"}},[s._v('"id"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(",")]),s._v(" \n "),a("span",{pre:!0,attrs:{class:"token property"}},[s._v('"role"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[s._v(":")]),s._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[s._v('""')]),s._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("}")]),s._v("\n")])]),s._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[s._v("1")]),a("br"),a("span",{staticClass:"line-number"},[s._v("2")]),a("br"),a("span",{staticClass:"line-number"},[s._v("3")]),a("br"),a("span",{staticClass:"line-number"},[s._v("4")]),a("br"),a("span",{staticClass:"line-number"},[s._v("5")]),a("br"),a("span",{staticClass:"line-number"},[s._v("6")]),a("br")])])])}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/book/assets/js/27.f3e5e360.js b/book/assets/js/27.f3e5e360.js new file mode 100644 index 000000000..2b4dc4055 --- /dev/null +++ b/book/assets/js/27.f3e5e360.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{506:function(e,t,n){"use strict";n.r(t);var a=n(65),s=Object(a.a)({},(function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[n("h1",{attrs:{id:"technologies"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#technologies"}},[e._v("#")]),e._v(" Technologies")]),e._v(" "),n("h2",{attrs:{id:"frontend"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#frontend"}},[e._v("#")]),e._v(" Frontend")]),e._v(" "),n("p",[e._v("Make sure you have the following software installed on your development machine:")]),e._v(" "),n("ul",[n("li",[e._v("Node.js v16 and NPM v8")])]),e._v(" "),n("p",[e._v("The frontend is developed with [Angular][angular], relies on the Angular CLI and is written in Typescript.\nStyling in ALEX is done with [Bootstrap v4][bootstrap] and SASS stylesheets.\nAll frontend files can be found in "),n("em",[e._v("frontend/src/main/javascript")]),e._v(".")]),e._v(" "),n("h2",{attrs:{id:"backend"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#backend"}},[e._v("#")]),e._v(" Backend")]),e._v(" "),n("p",[e._v("Make sure you have the following software installed on your development machine:")]),e._v(" "),n("ul",[n("li",[e._v("Java JDK 17")]),e._v(" "),n("li",[e._v("Maven 3.8.*")])]),e._v(" "),n("h3",{attrs:{id:"maven-goals"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#maven-goals"}},[e._v("#")]),e._v(" Maven goals")]),e._v(" "),n("p",[e._v("Make sure you "),n("code",[e._v("mvn install")]),e._v("ed ALEX once before executing any of the following commands.")]),e._v(" "),n("table",[n("thead",[n("tr",[n("th",[e._v("Command")]),e._v(" "),n("th",[e._v("Description")])])]),e._v(" "),n("tbody",[n("tr",[n("td",[n("code",[e._v("mvn test")])]),e._v(" "),n("td",[e._v("Execute all backend unit tests.")])]),e._v(" "),n("tr",[n("td",[n("code",[e._v("mvn verify")])]),e._v(" "),n("td",[e._v("Execute all backend unit and integration tests.")])]),e._v(" "),n("tr",[n("td",[n("code",[e._v("mvn checkstyle:check -Pcode-analysis")])]),e._v(" "),n("td",[e._v("Check if the code style is according to the specifications.")])]),e._v(" "),n("tr",[n("td",[n("code",[e._v("mvn spotbugs:check -Pcode-analysis")])]),e._v(" "),n("td",[e._v("Execute static code analysis with Spotbugs.")])]),e._v(" "),n("tr",[n("td",[n("code",[e._v("mvn spring-boot:run")])]),e._v(" "),n("td",[e._v("Start the REST API of ALEX.")])])])])])}),[],!1,null,null,null);t.default=s.exports}}]); \ No newline at end of file diff --git a/book/assets/js/28.05cd8897.js b/book/assets/js/28.05cd8897.js new file mode 100644 index 000000000..e88d74135 --- /dev/null +++ b/book/assets/js/28.05cd8897.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{508:function(e,t,r){"use strict";r.r(t);var o=r(65),a=Object(o.a)({},(function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("h1",{attrs:{id:"installation-docker"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#installation-docker"}},[e._v("#")]),e._v(" Installation (Docker)")]),e._v(" "),r("h2",{attrs:{id:"required-software"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#required-software"}},[e._v("#")]),e._v(" Required Software")]),e._v(" "),r("p",[e._v("In order to use ALEX on your local machine using Docker, make sure the following software is installed:")]),e._v(" "),r("p",[r("strong",[e._v("Linux")])]),e._v(" "),r("ul",[r("li",[e._v("Docker (v20.10.*) and")]),e._v(" "),r("li",[e._v("Docker Compose (v1.28.*)")])]),e._v(" "),r("p",[r("strong",[e._v("Windows / Mac")])]),e._v(" "),r("ul",[r("li",[e._v("Docker for Windows")])]),e._v(" "),r("h2",{attrs:{id:"installation"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#installation"}},[e._v("#")]),e._v(" Installation")]),e._v(" "),r("p",[r("strong",[e._v("Windows / Linux / Mac (Intel)")])]),e._v(" "),r("ol",[r("li",[r("a",{attrs:{href:"https://github.com/LearnLib/alex/releases",target:"_blank",rel:"noopener noreferrer"}},[e._v("Download"),r("OutboundLink")],1),e._v(" the "),r("code",[e._v("docker-compose.alex-3.0.0.yml")]),e._v(" file.")]),e._v(" "),r("li",[e._v("Run "),r("code",[e._v("docker-compose -f docker-compose.alex-3.0.0.yml up")]),e._v(".")]),e._v(" "),r("li",[e._v("Wait until the command line prints something like "),r("code",[e._v("Started App in XX.XXX seconds")]),e._v(".")]),e._v(" "),r("li",[e._v("Open "),r("a",{attrs:{href:"http://127.0.0.1/",target:"_blank",rel:"noopener noreferrer"}},[e._v("http://127.0.0.1/"),r("OutboundLink")],1),e._v(" in a web browser to access the frontend.")])]),e._v(" "),r("p",[r("strong",[e._v("Mac (ARM)")])]),e._v(" "),r("ol",[r("li",[r("a",{attrs:{href:"https://github.com/LearnLib/alex/releases",target:"_blank",rel:"noopener noreferrer"}},[e._v("Download"),r("OutboundLink")],1),e._v(" the "),r("code",[e._v("docker-compose.alex-3.0.0.yml")]),e._v(" file.")]),e._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/LearnLib/alex/releases",target:"_blank",rel:"noopener noreferrer"}},[e._v("Download"),r("OutboundLink")],1),e._v(" the "),r("code",[e._v("docker-compose.overrides.m1.yml")]),e._v(" file.")]),e._v(" "),r("li",[e._v("Run "),r("code",[e._v("docker-compose -f docker-compose.alex-3.0.0.yml -f docker-compose.overrides.m1.yml up")]),e._v(".")]),e._v(" "),r("li",[e._v("Wait until the command line prints something like "),r("code",[e._v("Started App in XX.XXX seconds")]),e._v(".")]),e._v(" "),r("li",[e._v("Open "),r("a",{attrs:{href:"http://127.0.0.1/",target:"_blank",rel:"noopener noreferrer"}},[e._v("http://127.0.0.1/"),r("OutboundLink")],1),e._v(" in a web browser to access the frontend.")])]),e._v(" "),r("h2",{attrs:{id:"credentials"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#credentials"}},[e._v("#")]),e._v(" Credentials")]),e._v(" "),r("p",[e._v("After the first start, you can log in as an admin using the account below:")]),e._v(" "),r("p",[e._v("Email: "),r("em",[e._v("admin@alex.example")]),e._v(" "),r("br"),e._v("\nPassword: "),r("em",[e._v("admin")])])])}),[],!1,null,null,null);t.default=a.exports}}]); \ No newline at end of file diff --git a/book/assets/js/29.e04fb3a6.js b/book/assets/js/29.e04fb3a6.js new file mode 100644 index 000000000..53467ef51 --- /dev/null +++ b/book/assets/js/29.e04fb3a6.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[29],{509:function(t,s,e){"use strict";e.r(s);var n=e(65),a=Object(n.a)({},(function(){var t=this.$createElement,s=this._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[s("h1",{attrs:{id:"installation-kubernetes"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#installation-kubernetes"}},[this._v("#")]),this._v(" Installation (Kubernetes)")]),this._v(" "),s("p",[this._v("TBD")])])}),[],!1,null,null,null);s.default=a.exports}}]); \ No newline at end of file diff --git a/book/assets/js/3.d2cd25a4.js b/book/assets/js/3.d2cd25a4.js new file mode 100644 index 000000000..d288b5519 --- /dev/null +++ b/book/assets/js/3.d2cd25a4.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[3],{436:function(e,t,s){e.exports=s.p+"assets/img/learner-setup-1.063c1ff2.png"},437:function(e,t,s){e.exports=s.p+"assets/img/learner-setup-2.0d6cd1ae.png"},438:function(e,t,s){e.exports=s.p+"assets/img/learning-1.d0fe7148.jpg"},439:function(e,t,s){e.exports=s.p+"assets/img/learning-2.4595c3b7.jpg"},440:function(e,t,s){e.exports=s.p+"assets/img/sample-1.1e7bb236.jpg"},441:function(e,t,s){e.exports=s.p+"assets/img/sample-2.09ccc5b9.jpg"},442:function(e,t,s){e.exports=s.p+"assets/img/resuming-1.4d6fa43e.jpg"},443:function(e,t,s){e.exports=s.p+"assets/img/resuming-2.2c5ffbd8.jpg"},444:function(e,t,s){e.exports=s.p+"assets/img/resuming-3.9ce1f361.jpg"},445:function(e,t,s){e.exports=s.p+"assets/img/results-compare-1.9adc7c86.jpg"},446:function(e,t,s){e.exports=s.p+"assets/img/results-compare-2.654497ba.jpg"},447:function(e,t,s){e.exports=s.p+"assets/img/results-compare-3.0a6255d9.jpg"},448:function(e,t,s){e.exports=s.p+"assets/img/results-compare-4.85ef950f.jpg"},449:function(e,t,s){e.exports=s.p+"assets/img/statistics-1.3108a08a.jpg"},450:function(e,t,s){e.exports=s.p+"assets/img/statistics-2.76aea7c6.jpg"},451:function(e,t,s){e.exports=s.p+"assets/img/statistics-3.678269c3.jpg"},452:function(e,t,s){e.exports=s.p+"assets/img/statistics-4.488847b3.jpg"},453:function(e,t,s){e.exports=s.p+"assets/img/counters-1.cf7959f2.jpg"},454:function(e,t,s){e.exports=s.p+"assets/img/counters-2.6932003d.jpg"},455:function(e,t,s){e.exports=s.p+"assets/img/counters-3.a316388a.jpg"},456:function(e,t,s){e.exports=s.p+"assets/img/counters-4.61a6bb76.jpg"},513:function(e,t,s){"use strict";s.r(t);var a=s(65),n=Object(a.a)({},(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[a("h1",{attrs:{id:"learning"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#learning"}},[e._v("#")]),e._v(" Learning")]),e._v(" "),a("h2",{attrs:{id:"creating-a-learner-setup"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#creating-a-learner-setup"}},[e._v("#")]),e._v(" Creating a learner setup")]),e._v(" "),a("p",[e._v("In order to start learning an application, a learner setup has to be configured.\nSuch a setup always consists of the following components:")]),e._v(" "),a("ul",[a("li",[e._v("An input alphabet (set of symbols)")]),e._v(" "),a("li",[e._v("A symbol to reset the application")]),e._v(" "),a("li",[e._v("A learning algorithm")]),e._v(" "),a("li",[e._v("A parametrized equivalence oracle")]),e._v(" "),a("li",[e._v("A list of target URLs")]),e._v(" "),a("li",[e._v("A web browser")])]),e._v(" "),a("p",[a("img",{attrs:{src:s(436),alt:"Learning"}})]),e._v(" "),a("p",[e._v("In the setup view ("),a("strong",[e._v("Learning > Setup")]),e._v("), the list of created learner setups is displayed.\nTo create a new setup, click on the "),a("em",[e._v("New Setup")]),e._v("-button.")]),e._v(" "),a("p",[a("img",{attrs:{src:s(437),alt:"Learning"}})]),e._v(" "),a("ol",[a("li",[e._v("Select a symbol that works as a system reset in the "),a("strong",[e._v("Reset")]),e._v("-section")]),e._v(" "),a("li",[e._v("Select all symbols that should be included in the input alphabet from the tree view in the left column")]),e._v(" "),a("li",[e._v("Optionally, select a symbol in the "),a("strong",[e._v("Post")]),e._v("-section.\nThis symbol will be executed after each membership query.")])]),e._v(" "),a("p",[e._v("You can start the learning process with the default configuration by clicking on "),a("strong",[e._v("Start learning")]),e._v(".\nYou can, however also adjust certain settings such as the equivalence test strategy or the target web browser.\nThe corresponding settings can be configured via the tabset on the right.")]),e._v(" "),a("p",[e._v("Here, in the tab "),a("strong",[e._v("Learner")]),e._v(", select a learning algorithm first.\nPer default, the "),a("em",[e._v("TTT")]),e._v(" algorithm is preselected because it usually performs better than the other available options.")]),e._v(" "),a("p",[e._v("Then, configure the equivalence approximation strategy:")]),e._v(" "),a("definition",{attrs:{term:"Random word"}},[e._v("\n The "),a("em",[e._v("Random Word")]),e._v(" EQ oracle approximates an equivalence query by generating random words from the input alphabet and executes them on the system. \n The oracles expects three parameters: "),a("em",[e._v("minLength (> 0)")]),e._v(" defines the minimum length of a generated word, "),a("em",[e._v("maxLength (>= minLength)")]),e._v(" the maximum length and "),a("em",[e._v("numberOfWords (> 0)")]),e._v(" the amount of randomly generated words to test.\n")]),e._v(" "),a("definition",{attrs:{term:"Complete"}},[e._v("\n The "),a("em",[e._v("Complete")]),e._v(" EQ oracle generates all possible words from an alphabet within some limits. \n "),a("em",[e._v("minDepth (> 0)")]),e._v(" describes the minimum length of word, "),a("em",[e._v("maxDepth (>= minDepth)")]),e._v(" the maximum length.\n")]),e._v(" "),a("definition",{attrs:{term:"W-Method"}},[e._v("\n The "),a("em",[e._v("W-Method")]),e._v(" EQ oracle generates words based on a transition coverage of the graph under the assumption of "),a("em",[e._v("maxDepth")]),e._v(" additional states.\n")]),e._v(" "),a("definition",{attrs:{term:"Sample"}},[e._v("\n If this oracle is chosen, counterexamples are searched and specified manually by the user.\n")]),e._v(" "),a("definition",{attrs:{term:"Hypothesis"}},[e._v("\n Uses an ideal model of an application to search for differences and uses them as counterexamples.\n Note that the input alphabets should be the same.\n")]),e._v(" "),a("definition",{attrs:{term:"Test Suite"}},[e._v("\n Uses all tests in a test suite for the counterexample search.\n Tests that do not use the same symbols from the model's input alphabet are skipped.\n This oracle is especially useful when having generated a test suite from a previously learned model.\n")]),e._v(" "),a("p",[e._v("In the "),a("strong",[e._v("WebDriver")]),e._v(" tab you can configure which web browser is used for accessing the target web application during the learning process.\nEach web driver has individual options which are displayed once you select a web browser from the select input.")]),e._v(" "),a("p",[e._v("Under the "),a("strong",[e._v("Environments")]),e._v(" tab, all URLs that are registered to the project are listed.\nSelect the ones where membership queries should be posed to.\nIf more than one URL is selected, membership query batches will be parallelized automatically.")]),e._v(" "),a("p",[e._v("Save the configuration with a click on the "),a("strong",[e._v("Save")]),e._v("-button so that it appears in the list of learner setups or execute the setup immediately.")]),e._v(" "),a("h2",{attrs:{id:"learning-2"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#learning-2"}},[e._v("#")]),e._v(" Learning")]),e._v(" "),a("p",[a("img",{attrs:{src:s(438),alt:"Learning"}})]),e._v(" "),a("p",[e._v("After having started a learning process and while the learner is active, ALEX shows you a loading screen where you find different information about the current process.\nIn the top half, several statistics and the membership queries that are being executed at the moment are displayed.\nBelow, the current state of the model is displayed.\nYou can navigate through all intermediate models "),a("span",{staticClass:"label"},[e._v("1")]),e._v(" or view details about the current step, change the layout of the model and export the model in the menu "),a("span",{staticClass:"label"},[e._v("2")]),e._v(".")]),e._v(" "),a("p",[e._v("Hypotheses are represented as Mealy machines and represent the learned behavior of the target application.\nNodes are labeled from "),a("em",[e._v("0")]),e._v(" to "),a("em",[e._v("n")]),e._v(", where nodes represent the internal states of the target application and state "),a("em",[e._v("0")]),e._v(" (visualised by a green node) is the initial state.\nEdges denote transitions from one state to another where the edge labels show the symbols whose execution led to the transition into another state.\nEdge labels have the following pattern:")]),e._v(" "),a("ul",[a("li",[e._v(" / Ok")]),e._v(" "),a("li",[e._v(" / Failed ()")]),e._v(" "),a("li",[e._v(" / ")])]),e._v(" "),a("p",[e._v('where is the name of the symbol and the text after the "/" displays the output of the system.\nIn ALEX, the output of the system is interpreted as '),a("em",[e._v('"Ok"')]),e._v(", if all actions of a symbol have been executed successfully.\nOn the other hand "),a("em",[e._v('"Failed (n)"')]),e._v(" means that the execution failed on the "),a("em",[e._v("n")]),e._v("-th action of the symbol.\nAs you may remember, in a previous section we introduced the possibility to define custom outputs.\nCustom success or error outputs for a symbol have a higher priority over the default ones.")]),e._v(" "),a("p",[a("img",{attrs:{src:s(439),alt:"Learning"}})]),e._v(" "),a("p",[e._v("After some time, when no more counterexamples can be found, the learner finishes and the final hypothesis is presented like above.\nFrom here on, you can, if you find it necessary, configure how the learning process should be continued.\nYou can also select the equivalence oracle "),a("em",[e._v("Sample")]),e._v(" and search for counterexamples by yourself, which is explained in the following.")]),e._v(" "),a("h3",{attrs:{id:"stopping-a-learning-process"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#stopping-a-learning-process"}},[e._v("#")]),e._v(" Stopping a learning process")]),e._v(" "),a("p",[e._v("At each point of time during a learning process, you can abort it by clicking on the "),a("strong",[e._v("Abort")]),e._v("-button beside the loading indicator.\nAfter clicking on the button, the current membership query (batch) is still executed, but after that, the process terminates gracefully.\nModels that have been inferred up to the point of termination are still available in the learning result.")]),e._v(" "),a("h3",{attrs:{id:"finding-counterexamples-manually"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#finding-counterexamples-manually"}},[e._v("#")]),e._v(" Finding counterexamples manually")]),e._v(" "),a("p",[e._v("Beside automated strategies for finding counterexamples, there is the option to search for counterexamples by hand directly on a model.")]),e._v(" "),a("p",[a("img",{attrs:{src:s(440),alt:"Sample"}})]),e._v(" "),a("p",[e._v("Therefore, select the equivalence oracle "),a("em",[e._v("Sample")]),e._v(" from the select input in the sidebar.\nThen, click together a word by clicking on the edge labels of the hypothesis.\nAfter that, click on "),a("span",{staticClass:"label"},[e._v("1")]),e._v(" to check if the word actually is a counterexample.")]),e._v(" "),a("p",[a("img",{attrs:{src:s(441),alt:"Sample"}})]),e._v(" "),a("p",[e._v("If this is the case, a notification will pop up and the actual system output of the word will be displayed at "),a("span",{staticClass:"label"},[e._v("3")]),e._v(".\nFinally, click on the "),a("em",[e._v("Resume")]),e._v(" button to initiate the refinement of the model given your counterexample.")]),e._v(" "),a("h3",{attrs:{id:"resuming-a-previous-learning-process"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#resuming-a-previous-learning-process"}},[e._v("#")]),e._v(" Resuming a previous learning process")]),e._v(" "),a("p",[e._v("The learning process usually takes a lot of time when learning models from web applications.\nThe more annoying it is if the learning process is interrupted due to various reasons and you have to start learning from the beginning.\nLuckily, there is the possibility to resume an old process from an intermediate model.")]),e._v(" "),a("p",[a("img",{attrs:{src:s(442),alt:"Resuming 1"}})]),e._v(" "),a("p",[e._v("In the results overview, expand the dropdown menu on the corresponding result and click on the item labeled by "),a("em",[e._v("Continue learning")]),e._v(" "),a("span",{staticClass:"label"},[e._v("1")]),e._v(".")]),e._v(" "),a("p",[a("img",{attrs:{src:s(443),alt:"Resuming 2"}})]),e._v(" "),a("p",[e._v("You are being redirected to the view you should be familiar with from the learning process.\nHere, simply select the step "),a("span",{staticClass:"label"},[e._v("2")]),e._v(" you want to continue learning from and configure the equivalence oracle according to your needs.\nFinally, click on "),a("span",{staticClass:"label"},[e._v("3")]),e._v(" to resume the learning process.")]),e._v(" "),a("div",{staticClass:"alert alert-info"},[e._v("\n When resuming a learning process and using the random equivalence oracle, make sure you use a different seed that in the run before.\n Otherwhise, membership queries are posed that have been posed before, which is not effective.\n")]),e._v(" "),a("p",[a("img",{attrs:{src:s(444),alt:"Resuming 3"}})]),e._v(" "),a("h4",{attrs:{id:"adding-new-input-symbols"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#adding-new-input-symbols"}},[e._v("#")]),e._v(" Adding new input symbols")]),e._v(" "),a("p",[e._v("You can add additional input symbols that should be included in the next iteration of a learning process.\nThis allows an incremental model construction.\nIn order to do so")]),e._v(" "),a("ol",[a("li",[e._v("Resume a learning process")]),e._v(" "),a("li",[e._v("In the right sidebar, open the tab "),a("strong",[e._v("Symbols")])]),e._v(" "),a("li",[e._v("Select the symbols that you want to add.\nSymbols that are already included in the model are ignored")]),e._v(" "),a("li",[e._v("Click the "),a("strong",[e._v("Resume")]),e._v("-button.\nFor each new symbol, a new step is generated and finally, an equivalence test is performed.")])]),e._v(" "),a("h2",{attrs:{id:"test-generation"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#test-generation"}},[e._v("#")]),e._v(" Test generation")]),e._v(" "),a("p",[e._v("ALEX allows you to generate test suites from a learned model automatically according to certain strategies, since each path of the model corresponds to a test case.\nFor that purpose:")]),e._v(" "),a("ol",[a("li",[e._v("Open any learned model")]),e._v(" "),a("li",[e._v("Switch to the testing view by selecting the "),a("strong",[e._v("Tests")]),e._v(" item form the select menu on the top right")])]),e._v(" "),a("p",[e._v("We differentiate between automated and manual test generation strategies.\nOne option is select sequences to generate a test case from manually:")]),e._v(" "),a("ol",{attrs:{start:"3"}},[a("li",[e._v("Click the labels on the model in the corresponding order.\nThe sequence appears in the "),a("strong",[e._v("Generate test case")]),e._v(" widget.")]),e._v(" "),a("li",[e._v("Give the test case a name and click on the "),a("strong",[e._v("Generate")]),e._v("-button.\nAs a result, the test case will be created in the root test suite.")])]),e._v(" "),a("p",[e._v("There is also the possibility to generate a test suite from the model automatically using certain strategies.")]),e._v(" "),a("ol",{attrs:{start:"3"}},[a("li",[e._v("In the "),a("strong",[e._v("Generate test suite")]),e._v(" widget, select a corresponding strategy.\nNote that the "),a("em",[e._v("Discrimination tree")]),e._v(" strategy only provides state coverage, but results in a much smaller test suite than the other methods.\nThe "),a("em",[e._v("W-Method")]),e._v(" and the "),a("em",[e._v("Wp-Method")]),e._v(" both provide state and transition coverage, but result in bigger test suites and the generation process might take longer.")]),e._v(" "),a("li",[e._v("Click on the "),a("strong",[e._v("Generate")]),e._v("-button to generate the test suite")])]),e._v(" "),a("h2",{attrs:{id:"cloning-learning-experiments"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#cloning-learning-experiments"}},[e._v("#")]),e._v(" Cloning learning experiments")]),e._v(" "),a("p",[e._v("Sometimes it may be useful to copy existing learning experiments, e.g. for the purpose of testing other equivalence strategies from a previously learned step.\nTherefore")]),e._v(" "),a("ol",[a("li",[e._v("Navigate to "),a("strong",[e._v("Learning > Results")]),e._v(" in the sidebar")]),e._v(" "),a("li",[e._v("Open the menu for the corresponding learning experiment")]),e._v(" "),a("li",[e._v("Click on "),a("strong",[e._v("Clone")])])]),e._v(" "),a("h2",{attrs:{id:"result-analysis"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#result-analysis"}},[e._v("#")]),e._v(" Result analysis")]),e._v(" "),a("p",[e._v("Each learning process experiment and its results, including the models, statistics etc. are saved in the database.\nThis section deals with possibilities to use the learned models for a further analysis.")]),e._v(" "),a("h3",{attrs:{id:"model-comparison"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#model-comparison"}},[e._v("#")]),e._v(" Model comparison")]),e._v(" "),a("p",[a("img",{attrs:{src:s(445),alt:"Comparing 1"}})]),e._v(" "),a("p",[e._v("All results from the learning processes are saved in the database and are listed in the view under "),a("em",[e._v("Results")]),e._v(" in the group "),a("em",[e._v("Learning")]),e._v(".\nClick on the test number of a result to display the model that has been learned during the corresponding learning process.")]),e._v(" "),a("p",[a("img",{attrs:{src:s(446),alt:"Comparing 2"}})]),e._v(" "),a("p",[e._v("The view here is the same as the one that is displayed during the learning process.\nThe difference is that other models from the same project, from other projects or from a previously exported JSON file can be added and displayed side by side.\nClick on "),a("span",{staticClass:"label"},[e._v("1")]),e._v(" to open a modal window with the corresponding options.")]),e._v(" "),a("p",[a("img",{attrs:{src:s(447),alt:"Comparing 3"}})]),e._v(" "),a("p",[e._v("In ALEX, there are two options to compare two hypotheses, which are available at "),a("span",{staticClass:"label"},[e._v("2")]),e._v(".\nThe "),a("strong",[e._v("separating word")]),e._v(" is the shortest word where the output of two model differ.\nIf no separating word can be found, both models are identical.\nOn the other side, such a word can indicate two things:")]),e._v(" "),a("ol",[a("li",[e._v("Different or differently configured equivalence oracles have been used in both test runs and one did not find as many counterexamples as the other.")]),e._v(" "),a("li",[e._v("The system under learning has changed, be it because a regression between the two test runs.\nIn this case, the separating word gives you an entry point for debugging the application or it represents the change correctly.")])]),e._v(" "),a("p",[e._v("Then, you can calculate the "),a("strong",[e._v("difference")]),e._v(" between two models.\nIn contrast to the separating word, "),a("em",[e._v("all")]),e._v(" words are calculated where both models differ.\nThe result is displayed as a tree, where the paths with same suffixes have been merged for a better overview, like depicted in the picture below, where the difference is displayed in a third panel.")]),e._v(" "),a("p",[a("img",{attrs:{src:s(448),alt:"Comparing 4"}})]),e._v(" "),a("p",[e._v("There are two options for calculating the difference between two models in the dropdown menu "),a("span",{staticClass:"label"},[e._v("2")]),e._v(".\nThere are two options because of the way the difference is calculated.\nAs a basis, the transition coverage of one model is used and every word is tested on the other model.\nAs a consequence there might be different results depending on which way is used.")]),e._v(" "),a("h3",{attrs:{id:"statistics"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#statistics"}},[e._v("#")]),e._v(" Statistics")]),e._v(" "),a("p",[e._v("In ALEX, some statistics about the learning processes are gathered automatically, that are:")]),e._v(" "),a("ul",[a("li",[e._v("The number of membership queries,")]),e._v(" "),a("li",[e._v("the number of equivalence queries,")]),e._v(" "),a("li",[e._v("the number of symbols that have been called and")]),e._v(" "),a("li",[e._v("the execution time.")])]),e._v(" "),a("p",[e._v("Each value is saved per learning step and separated by membership and equivalence oracle.")]),e._v(" "),a("p",[a("img",{attrs:{src:s(449),alt:"Statistics 1"}})]),e._v(" "),a("p",[e._v("In order to display statistics, go to the results overview, and click on the item "),a("span",{staticClass:"label"},[e._v("1")]),e._v(" on the corresponding result.")]),e._v(" "),a("p",[a("img",{attrs:{src:s(450),alt:"Statistics 2"}})]),e._v(" "),a("p",[e._v("Now, you will see some bar charts for the cumulated values over all learning steps.\nTo see the statistics for each individual learning step, click on "),a("span",{staticClass:"label"},[e._v("2")])]),e._v(" "),a("p",[a("img",{attrs:{src:s(451),alt:"Statistics 3"}})]),e._v(" "),a("p",[e._v("A line chart then displays the values that are listed above for each step.")]),e._v(" "),a("p",[a("img",{attrs:{src:s(452),alt:"Statistics 4"}})]),e._v(" "),a("p",[e._v("There is also the possibility to compare the statistics of multiple learning processes.\nIn this case, select all relevant results in the overview and click on "),a("span",{staticClass:"label"},[e._v("3")]),e._v(".\nThe only difference here is that the displayed values are not separated by oracle.")]),e._v(" "),a("h2",{attrs:{id:"counters"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#counters"}},[e._v("#")]),e._v(" Counters")]),e._v(" "),a("p",[e._v("As you may recall, counters are integer values that are created, modified and used during a learning process and persisted in the database over multiple learning processes.")]),e._v(" "),a("p",[a("img",{attrs:{src:s(453),alt:"Counters 1"}})]),e._v(" "),a("p",[e._v("On the counters page, which you can access by clicking on the item "),a("em",[e._v("Counters")]),e._v(" "),a("span",{staticClass:"label"},[e._v("1")]),e._v(" in the sidebar, the values of existing counters can be edited and new counters can be created.")]),e._v(" "),a("p",[e._v("For creating a new counter with a preset start value, click on "),a("span",{staticClass:"label"},[e._v("2")]),e._v(" which opens a modal window.")]),e._v(" "),a("p",[a("img",{attrs:{src:s(454),alt:"Counters 2"}})]),e._v(" "),a("p",[e._v("Here, insert a unique name and the value in the input fields and click on "),a("em",[e._v("Create")]),e._v(" "),a("span",{staticClass:"label"},[e._v("3")]),e._v(".\nIf the counter has been created successfully, the modal dialog is closed and it appears in the list.")]),e._v(" "),a("p",[a("img",{attrs:{src:s(455),alt:"Counters 3"}})]),e._v(" "),a("p",[a("img",{attrs:{src:s(456),alt:"Counters 4"}})]),e._v(" "),a("p",[e._v("For editing the value of an existing counter, click on "),a("span",{staticClass:"label"},[e._v("4")]),e._v(" in the dropdown menu, update the value in the form and finally, click on "),a("em",[e._v("Update")]),e._v(".")])],1)}),[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/book/assets/js/30.8957b82f.js b/book/assets/js/30.8957b82f.js new file mode 100644 index 000000000..0966c457f --- /dev/null +++ b/book/assets/js/30.8957b82f.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[30],{514:function(e,t,n){"use strict";n.r(t);var i=n(65),o=Object(i.a)({},(function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[n("h1",{attrs:{id:"model-checking"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#model-checking"}},[e._v("#")]),e._v(" Model checking")]),e._v(" "),n("p",[e._v("ALEX allows to automatically verify properties of learned models using LTL model checking using the LTSmin library "),n("a",{attrs:{href:"ltsmin"}},[e._v("LTSmin")]),e._v(".")]),e._v(" "),n("h2",{attrs:{id:"define-ltl-formulas"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#define-ltl-formulas"}},[e._v("#")]),e._v(" Define LTL formulas")]),e._v(" "),n("p",[e._v("Currently, ALEX only supports model checking using LTL formulas.\nTo define formulas that you want to have checked later on:")]),e._v(" "),n("ol",[n("li",[n("p",[e._v("In the sidebar, click on "),n("strong",[e._v("Learning > Lts Formulas")])])]),e._v(" "),n("li",[n("p",[e._v("Click on the "),n("strong",[e._v("Create")]),e._v("-button in the action bar")])]),e._v(" "),n("li",[n("p",[e._v("In the dialog, define a property using "),n("a",{attrs:{href:"ltl-syntax"}},[e._v("this syntax")]),e._v(" and give the formula an optional name.\nAdditionally, use the keywords "),n("em",[e._v("input")]),e._v(" and "),n("em",[e._v("output")]),e._v(" to query edge labels of the automaton, e.g.")]),e._v(" "),n("p",[n("code",[e._v('[](input == "Delete" -> output == "Ok")')])])]),e._v(" "),n("li",[n("p",[e._v("Click on "),n("strong",[e._v("Create")])])])]),e._v(" "),n("h2",{attrs:{id:"verifying-properties"}},[n("a",{staticClass:"header-anchor",attrs:{href:"#verifying-properties"}},[e._v("#")]),e._v(" Verifying properties")]),e._v(" "),n("ol",[n("li",[e._v("Open any learned model")]),e._v(" "),n("li",[e._v("Select the model checking view by selecting the item "),n("strong",[e._v("Checking")]),e._v(" from the select menu on the top right")]),e._v(" "),n("li",[e._v("Select all formulas that you want to have verified or enter additional properties")]),e._v(" "),n("li",[e._v("Optionally, change the parameters for minimum unfolds and the multiplier")]),e._v(" "),n("li",[e._v("Click on the "),n("strong",[e._v("Run checks")]),e._v("-button")]),e._v(" "),n("li",[e._v("If a counterexample could be found, it is displayed below the corresponding formula")])])])}),[],!1,null,null,null);t.default=o.exports}}]); \ No newline at end of file diff --git a/book/assets/js/4.2ea60ef6.js b/book/assets/js/4.2ea60ef6.js new file mode 100644 index 000000000..d2889426f --- /dev/null +++ b/book/assets/js/4.2ea60ef6.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[4],{460:function(e,t,a){e.exports=a.p+"assets/img/symbols-1.1ed50e85.jpg"},461:function(e,t,a){e.exports=a.p+"assets/img/symbols-search.66841f44.jpg"},462:function(e,t,a){e.exports=a.p+"assets/img/symbols-archive.7702ad2c.jpg"},463:function(e,t,a){e.exports=a.p+"assets/img/export-1.4ab43898.jpg"},464:function(e,t,a){e.exports=a.p+"assets/img/import-1.20ad22e4.jpg"},465:function(e,t,a){e.exports=a.p+"assets/img/symbol-parameters-2.ecb74dba.jpg"},466:function(e,t,a){e.exports=a.p+"assets/img/symbol-parameters-1.84e3bf86.jpg"},467:function(e,t){e.exports="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAkAAAADLCAYAAACGciwEAAAABHNCSVQICAgIfAhkiAAAIABJREFUeJzt3V9oG9eiLvAvFx1YAhdG4IIGEvAUBzolhcq0cCVuHqJLHiKTQiwaaEQLzewUWrmBxm7htLp5yFF6oMdOIbFa2DlqIUEJNNiFHaI8BJSHXOQLCVYgwQrE7GWwYQQ1aKAGDWyB78PYiuU/iv/L0nw/EK2k0XjNimbNpzVrZh1YWFhYABEREZGL/I9mF4CIiIhorzEAERERkeswABEREZHreFa9UgWseQv2vI1KtdKEIhERERHtDK/HC9EhoHQodannQN0g6CpQmiutWoiIiIioZS127vg7/bV8UxeALMuC8AiGHyIiImovVcC2bSidCoAVY4DseZvhh4iIiNqPxwlAS+oCEMf8EBERUbtannN4FRgRERG5DgMQERERuQ4DEBEREbkOAxARERG5DgMQERERuQ4DEBEREbkOAxARERG5DgMQERERuQ4DEBEREbkOAxARERG5zo4GoOKLIkLBEFK/pHZytZtSeFJA9HQU4WNhJC4mgGrTikJERET7VMv1AA1eGMTwT8Prvj90dQjho2FkbmaQe5hD7lFuz8uw1+vZD9ppW4iIqP3tWgCSUxKhYAiZmxn0n+9H+FgYg98Owrbt2nupaykYnxtOb813CdjzNgpPCggFQ8jezTrrmXaWTV9PI3o6ivx4HqO/j8L43Fjz79q2DdWvojRXAqqA+qa6bhmLL4ro/7If4eNhRE9HkbmdAYBNlWE3tqXROgEgczuDaJ/Ty9V/vh9myaz73NL6l7bndctnbmZqfyf1Swr58Tx6P+xF74e9KDwt1MpVeFJA7NMYwsfCzrZPSwBYc1vWW3bdMt58VUbjrFH3d4mIiHba7vUAeZz/jP0xhr6TfeiN9CL/KI/s/Wztvez9LPo/70fs0xhyD3MY/WO04SpHrowAACInIhj+ce3ehsCRANI30xj4egDxL+PQj+hrLmdZFuJfxVGpVpC6lkLkeASpqymnfJspw25sS4N1yimJWzdvIXwsjPRvaUwWJ5G6mqr73FKd97zbs+HlYx/HoB5SkbmRQfZuFgNfDaDyVwXpv6ed+pqzMPDNAPRuHWN3xgCgVu6V29Jo2bXKWHxRROrnFGIfx5C5nYGv04eRqyMN64+IiGg7dv0UWCgYQvh4GGc+OQMAtZ4AAAgfCyPwfgDGJwaEEBh/PN5wXT7FBwDwvuGFoiir3s/czCD7IIvyn2Ukvksg9kkMyUtJjP0xtmrZ/KM87HkbsY9j0N/WYXzmlCH3oPEps/XKsNPbst46tW4N97L3EP8qDu2gBu2QVlenABD8n0HEPolBP6JvaPlQMITwsTAixyMAnCATPh7GO/o7kLPOsrlHOdi2jd5IL5ROBb0nejFRmIA1Z63alkbLrlXGpXFa+cd5yJcSyYtJpH9NN6w/IiKi7fDs9h9QOp2Du6/DOUguH5S89B48zsGzbJW3/HcKTwtI/ZxC/Ms4isUi0r+loes6cg9zCB0NrVrenHNOA9VOkXkAn89Xe32zdnJbGq3Tsiwkf0hiojABr9eLcrkMVa0/zaceevV8I8sv/R2v8AIAfG86/1aiQ9T+vZa2J/5VvO6zZsmE1qXVvdZoWdEhVpVRP6LDOGsg83sG+Ud5CCEQOxODcW7t05xERETbtesBqBHLWuwRqAKVvyrQujQI4Rwgy/POQXR5r0Ej8uXieJRTUdgnbMTOxvC3z/8G35s+hI+GVy2vdjoHYPNPEzqcXohyuYyerp4tlWEnt6XROjO3nZCQvp6GfkRH9HS04To2u/x6lnp5hq4MoSfQU3tdeARs297wsks9SisZ5wwYnxkovigifSON9K9pRE9FX4VAIiKiHdTUq8ByD3MoPC0gfTMN27YRDAah+lXA44x/yY/nkbmVqS0vhAA8wGRxctVpHO2w0wuRuZNBeb4M/W0d5bITPHKPcqvCR+hoCKJDIHM7Azklkbqegm3biJyMbKkMO7ktjda5FDaklMjczqD8Zxn2vL1uuNrs8usJBoMQQiB7Nwtz1kTiYgLGWQN21V61LY2WXXM7H+TQG3EGXCuditND5UEtQBIREe20pgag8LEwRn4eQeZWxrkSa/EXf/zLOKw5C8P/NYy+U30A4Bw8PUD0wyjkS/lqIO+iwHsBxM/Hkb2bhfGZAXveRvKHJLQuDcM/Da8KGYqiIHXNWYdxzkDuYQ6DFwYRPhbeUhl2clsarfPMR2egHdYwdGUIxWIRyUtJwONc/r+WzS6/HtWvInkpCTkrYZwzUJ4rY/DbwVr4Wb4tDZddQ+hoCMH/FUTiYgKxj2OYeDyB5KVk7XQZERHRTjuwsLCwsPRETkun12KXyWmJ2McxGJ87pz1a2W5sSzvVDxER0X6xfNxqy90IkYiIiGi7mtIDRERERLTX2ANERERErsYARERERK7DAERERESuwwBERERErsMARERERK7DAERERESuwwBERERErsMARERERK7DAERERESuwwBERERErsMARERERK7jWfmCWTKbUQ4iIiKiPbMqAC1NEkZERETUTuS0rP0/T4ERERGR6zAAERERkeswABEREZHrMAARERGR6zAAERERkeswABEREZHrMAARERGR6zAAERERkeswABEREZHrrLoT9GZYcxbMORO2be9UeVqGEAJqpwqlU1n1npvrpZFGdUZERLSXthyArDkL5fkytC4NQoidLFNLsG27Nm/a8gO62+ulkfXqjIiIaK9t+RSYOWdC9auuPcgLIaD6VZhz9ZPHur1eGlmvzoiIiPbalgOQbduuP8gLIVad5mK9NLZWnREREe01DoImIiIi12EAIiIiItdhACIiIiLXYQAiIiIi12EAIiIiItdhACIiIiLX2dMAZM1ZCAVDSP+WXneZy/95Gdm72Q29XnhaQOK7xI6Xc6/tdL0QERFRY3sagEbvjiLaF92xA3bgvQCSPyR3ZF0AgCrwt7N/27n1bdBO18umbWe7m1RnRERE27GtucA2K3s3i9TVFIrFIorPi9CP6ACAxMUESrMl+P1+WPMWAkcCDV9fUnhSQPpGGsZZA5kbGfh8PkgpAQAjP4+g8LSAzI0MhBAw50z4OnwY+nEIhecFjP4+iqErQwCAy/9xGYH3A8iP5zH5chKX/+Myvv8/37dsvQBA+noa4+PjgAfQDmn4/t+/x/iT8ddud/h4uCXqjIiIaDv2LAAVnhYgOgT8B/0IHw9j7I8xfH/ke4z/33GUSiX896//DVSB3r5eAFj39fXkH+eRvZuFoigYvDCI/KM8fD4fJp5NIHc/B9EhkLiYwNjdMWiatuY6jLMG5JTc0wP5btRL4UkBuUc5ZG5kAACJ75ztVlV1zTIs3+7Ck8K+rzMiIqLt2rNTYKNjo+g94RysIyciyD3MwbZtTL6cRCCw2IPhcU5rAVj39fW8o78DRXEm2FRVFda8VXtddDhTU/QEeiCn5E5v2rbsRr1MPJtA6INQ7XnPBz0ovihuuEz7vc6IiIi2a096gOx5G7mHOcgpiXt379X+cu5hDqiuWLi64r8rX1+H8KyYf2u95dfY4sq/Ko1Xvkv2ol4aLbPh7d5HdUZERLQT9qQHKHs/i1AwhMytTO3x/b9/j7E/xqB1aygUCgCciUQLT53/X+/1zZJTEva8M/lm8XkRercOpUOBWTJXrdvr8cKu7t1EnbtVLz2BHuQf52vP84/zCBwJbHi793OdERER7YQ96QEavTuK/i/7614LHw3j8n9exjuH34G/04/YpzGofrU2ADh8NIzcg9yq1zdL69Yw/NMwTNMEPMDANwMQQkD1q4h9GoN2UHNOI1UBv98PVIH+L/sx8vPItrf7dXarXgLvBRA+GnauzvIAmqYhcjICAK/dbuOssa/rjIiIaCccWFhYWFh6IqcltK61B7uuVHhaeO24nGZbukps5OruHZhX1kMr1EsjzagzIiKivbA85/BO0EREROQ6e3ofoL0WeD+Akfd5WmYzWGdEROQG7AEiIiIi12EAIiIiItdhACIiIiLXYQAiIiIi19lyABJCwLbdfQM827YhRP0dqFkvja1VZ0RERHttywFI7VRhlkzXHuxt24ZZMqF21k8w6vZ6aWS9OiMiItprW74MXul0Jh6V09KVB3shBNROtVYPS9xeL42sV2dERER7bVv3AVI6FR7M1sB6ISIi2t84CJqIiIhchwGIiIiIXIcBiIiIiFyHAYiIiIhchwGIiIiIXIcBiIiIiFyHAYiIiIhchwGIiIiIXIcBiIiIiFxn1Z2g5bRsRjmIiIiI9syqAKR1ac0oBxEREdGuWt7Jw1NgRERE5DoMQEREROQ6DEBERETkOgxARERE5DoMQEREROQ6DEBERETkOgxARERE5DoMQEREROQ6DEBERETkOgxARERE5DoMQEREROQ6DEBERETkOgxARERE5DqrZoMnItqyarMLsEfYchK1PO7GRLRtpTkLI3cnkHsmYVl2s4uzqxRFIPyuhv6TPfB3Ks0uDhFtEQMQEW1LqWSh78csrCoghArhb3aJdpddBcYKJeSeZTH2bQR+P0MQUSviGCAi2roqMHR3wgk/HYo7flJ5nG21FrfdNaf9iNoMAxARbZldtZF/JiGE+3pBhFCQfyZhV9v7lB9Ru3LD77XV+IuNNsude0pjVedhzdsQHc0uTBN4nG1fqgd+R9bAtra1uOw77KrNtSwLckpCzkiUrXKzi0Mtwqf4oB3SoHVrUBT39XQQbRbb2tbjxnbONQHIsizkH+WhqipCwZBr/oFp+yzLgjlrIv8oj9BRfneIGmFb25rc2M65IwBVgeKLIlRVhX5Eb3ZpqMUoilJrDIovigi+H3TLnkO0OWxrW5Yb2zlXDIK2qzbMGRPqQbXZRaEWph5UYc6YHPRKtA62ta3PTe1c+wegxQGK5fmyK7r0aPcoioLyfPnVoFcieoVtbVtwUzvX/gGIiIiIaAUGICIiInIdBiAiIiJyHQYgIiIich0GoE2y5izYdvuPjqf2px5SMXhhEHJaNrsotA8sfR8KTwvNLgrRnmAA2iA5LWGcNRA5GUH4WBjJS8kdD0JyWiIUDCH9W3pH19tI9n4WxlkDsTMxRE9HMfjtIMxZ87WfKz4vInYmtgclpN1Smi1h+KdhvKW9hZ5AD1LXUgxDLrb0fegJ9OAt7a19H4Zq7eX1xu1l8UURoWAIqV9SW14HwLayHTEAbVDiYgKqX0X2fhaZmxkUnhc2HFQGLwxi+KfhXS7h5hWeFpC+nkbyhyQytzIY/X0UgXcDSN9wtktOSQx+O7jmZ/UjOjI3MntZXNpFhacF9J/vZxgiAE4w2KswtF/bx+XYVranNr/P486w5izIlxLJi8na3TL7TvYh+yCL+Bfxhp+Nno7CnDGBcWCyOIn039MovigidTWFyZeT8Pl86DvVh9jHq38hJC8lkXuUQ/p6GlqXhsKTAoauDsGcMaEd1pD4LgGtS4Ockoh9EkP8yzjGH49j8tkkej7oQfJSEkII9H7Yi+SlJALvBerWP1mchP62DtX/6qZlsU+cchSfFzH47SBEh0D6ehpyRkI7pCH7IIuBrweQvZtFKBhC5GQEiYsJaJqGQqEAc9ZEKBjCwDcDAJyGIflDEnbVhtalwfeGD/6D/jW3l/aHpTCE80DgvUCt51Pr0ppdNGqCpTA0/NMwtC7Naa8+ja1qT7Zis+3j2B9jtR+efSf76ta10Xa10TrYVroLe4A2wJxzujmX5koxZ03Ytg173n7tabCRKyMAgMiJCIZ/HIZlWYh/FUelWkHqWgqR4xGkrqaQvZ+t+9zYnTFk72eRvJiE1qXBmrMw8M0A9G4dY3fGAADDPy7+alqMsWN/jKHvZB96I73IP8rX1nnvH/fWbKxCH4SQf5xH6pcU5FT9r339iA6tS8PA1wMwzhmQ0xKmaWL01ihCwRDktISmOQdEOS0hpcTQj0NI/5rG6D9GYVkWUAUGvxuEcc5A5kYGkeMR3MvewzuH39lE7VMzsWeIltvpnqHNtI/mrImhK0PQujSMXBlB8WWxtp6NtquN1gGwrXQbBqANiH8Vr/03+lEU0Y+iSP+ahmmaSP6QbPhZn+IDAHjf8EJRFOQf5WHP24h9HIP+tg7jMwNCCOQe5GqfKT4rYujqEGKfxhA6GgIA5B7lYNs2eiO9UDoV9J7oxURhAtacVftcKBhC+HgYZz45AwCvPVBp3RrSv6RR/rMM4wvn3HbhyavGrLbjVgFzxkTs0xjgAWzbdn7ldDnvSSkR/zwOIQSUDucOsEIIFJ4WIDwCoaCzDT2BHti2Df3t1p4jyPuGFwf+7QAOHGjtx2atDEPD14YZhuDe78PKMNR/oX/TYWgz7WOhUACqwJmPzkDr1urG1WykXQXQcB2NsK1sTzwFtgH2/Pq9PI3eW8tSb5L65mJXqgfw+Xy11wEgP54HPIB8+ergUrbKAF6Fsdr6SiZEhwAAKJ3ODuXrcBqVjdzGXOvWkLiYQKKawNjdMQx8M4DM7Qy8Hi8q/6pA9auQ0xLeN7y1UyByWkJVVYgOATklob6p1ub+kdPOcyEEJl9O1u3AZasM9ZBaKy+1LjfME0QbV6lWdmQ9jdrHpTbQ53PaN3+nf0OfW67ROl6HbWX7YQDaY2qn8+U3/zShQ3fmzimX0dPVU1smejoKv9+P1NUU8uN5hIKh2i+loStD6Am8WlZ4BOTsDvwK9wB9p/qQ/i2NUqmESqVS636VL2XdzimlfLWDSwmtW6t/b/G5NWfVGhoAGH88Dr279X/RVP6qQAjR8nvPZn/160d0GGcN9J3qq/2i5S0h3Pt98B/0I3oqCuOs4Zw2Wvw+TL6c3HIZGrWP3g4vAOc5AJRKpQ19brlG69gwtpVtg6fAdtlSwzhZnHQuuTwagugQyNzOQE5JpK6nYNs2Iicjtc8oioLoqShUVUXqWgqoAsFgEEIIZO8658ITFxMwzhpb/iU+dmcMie8SdQew3IMcUAX0bh2lUqk2oWFxqlg7hw04g/X0w/qa7y1/rnQqkDNOOLPmLGRuZ6Ad5kDaVqIf0TF0ZQj/lP/E5LNJDHw9wMHQLuY/6Ef8qzgmChMwZ0yMXB3Z1mDozbSPwQ+CAIBbd25BTklkbr26smoj7SqAhutYD9vK9sUAtAGqqm7pPQCAB4h+GIV8KZG6moKiKE6oAWCcM5B7mMPghUGEj4XrPiaEgPGZASklxu6OQfWrSF5KQs5KGOcMlOfKzpUH4vVdpL0f9q46Nx85GYHP53PuadEXRfR0FNkHWQxdGYLoENA07dWgv5ey7tdI3a+ale8tex49GYVt2zDOGhj5eQRCCPS8W/+LjPYfhh5abqdDT51NtI/qQRXx83HIKYn+C/218TJ21d5wu9poHQDbSrc5sLCwsLD0RE7L9mvoFrtlM3cyvJywiYrPi0hcTGD099GWPlWQuZ1B7KNY253yWHV6ayMW962e82kIf5u1GxtklyQmrhpt931YdXprI9jW7oj90Fa2Uzu30vKc02abRvtJ6pcUJh5PAAC8wutcMcdv3L6xdJAbuMAeHtpi6KEdwbayOVjFtGviX8SBL5pdClqPOfP62/iTe/D70DxsK5uDY4CIiIjIdRiAiIiIyHUYgIiIiMh1XBOAfB0+Z84Voi2yLOvVXbaJaE1sa1ubm9o51wQgVVVhznKQH22dOWu+/r5PRC7Htra1uamda/8A5HEefr8fckai+LzIXye0KZZlofi8CDkj4ff7a98pIlqGbW1Lc2M71+ab5xAeAZ/ig67rME0T8pFEeb7c7GJRi/B1+KB0KtB1HT7FB+HhBIVEa2Fb27rc2M65IgDBA4gOARUqfB0+VLTKhmZKJwIAeACvxwshhDM7szv2GqLNY1vbulzYzrlgEx1CCAiPcOaNqSrNLg61Go/z69Y9ewzR1rCtbWEua+dcspmLlv5x+YuENstde8q+kDobgjlnI/mPiX2xHtoEtrWtyWXtnMs2d5E7t5qoZWS/DcOvCKAb0A+GEfs5h9BhFQMndGidAsWShcSdIuSfzvgS46iO2FEVihAoztkYvlvAhCyvuR7aQ2xraR9r/6vAiKjlGNcLAIDs0xL6b+ah+gRGPgmgWLLwv//LCTGJUzoAQD/kQ/yEhvRDid6fxmHN2xg4EVhzPURES5jPiWjfKdsVAIBtA+W/bESDGuABsgUT5b9sjD028f0pHb43Xl2pEjqswrRsJG5PoFyx11wPEdESBiAi2vf8HU7QGfksACDw6nXFi+JMGemHErGjGoJvB4AqkH4kkXpQbFJpiagVMAAR0b5Xspzem/7fnLE9S+yq83rqQRGphxI9qhfGMR3GMQ23/p9EhYNwiWgdHANERPuO/S/nv/pBAe1NH/JTJlAF+oIa1De9GD7Tg7HzIQiPQCSgIXcxgpDmgzlfgVwMS6iuXg8R0RJ39gDxVyFtljv3lOap2hh7UkLfe34MntQR/zWPwdsFxE/oGP0iCDlnI/FHAXbVRu6ZiR7Nh+THASgeQFo2Bm8XauOAVq6HiAgADiwsLCwsPZHTElqX1szy7CrLsiCnJOSMRNni7dlpY3yKD9ohDVq3BkXhjd1qqoBt2+g5n4bwt2+70Yhdkpi4akAI99w8jqiVLc85rtllLctC/lEeqqoiFAzxQEYbZlkWzFkT+Ud5hI7yu0NE1A7cEYCqQPFFEaqqQj+iN7s01GIURamFnuKLIoLvB92y5xARtS1XDIK2qzbMGRPqQbXZRaEWph5UYc6YtSuPiIiodbV/AKo6j/J8macuaFsURUF5vlz7ThERUetq/wBEREREtAIDEBEREbkOAxARERG5DgMQERERuQ4D0BbZ8zYsy2p2MYi2TD2kYvDCIOS0bHZRiIj2HAPQJtm2jeSlJMLHw4iciKD/y36YJXNX/paclggFQ0hfTzdcLno6ilAwtOaj+GL3Z8TO3s/COGsgdiaG6OkoBr8dhDn7+jopPi8idia26+WjtZVmSxj+aRhvaW+hJ9CD1LUUwxARuQYD0Calr6dReFpA5mYG2ftZ+P1+XL50ueFnBi8MYvin4V0r08DXA0heSiL+ZRwAEDoaQvJSEslLSaj+rd37aKNlLjwtIH09jeQPSWRuZTD6+ygC7waQvuGENjklMfjt4Jqf1Y/oyNzIbKl8tLMKTwvoP9/PMERErsH72W5S/nEefaf6oHU7c4kYnxuIfhSFbdvOfEArRE9HYc6YwDgwWZxE+u9pFF8UkbqawuTLSfh8PvSd6kPsY6cnZOyPMaR/c8JD38m+unWt97lQMFR7HwA0TUP4eBgAUHhSwNDVIZgzJrTDGhLfJaB1aUj/lkb672mkrqUQeD+A5KUkcg9zSP+WdnpwVpS598NeJC8lEXgvUFemyeIk9Lf1uqAV+8TZluLzIga/HYToEEhfT0POSGiHNGQfZDHw9QCyd7MIBUOInIwgcTEBTdNQKBRgzpoIBUMY+GYAgBOikj8kYVdtaF0afG/44D/or9UZ7aylMITzQOC9AIyzBiInI209TyARuQ97gBpYmgNq+cOet2HbzgMAvMJbmxRyLSNXRgAAkRMRDP84DMuyEP8qjkq1gtS1FCLHI0hdTSF7Pwtz1sTQlSFoXRpGroyg+LJYV5b1Prdu+ecsDHwzAL1bx9idMQDA8I9Or47xiQHtsIahK0MoPC3UTmMt/e3lZQaAe/+4tyr8AEDogxDyj/NI/ZKCnKrvMdCP6NC6NAx8PQDjnAE5LWGaJkZvjSIUDDmT0mnOQVVOS0gpMfTjENK/pjH6j1FnjFUVGPxuEMY5A5kbGUSOR3Avew/vHH7n9f+AtG3sGSKidsUA1EDfR32IfhSte5imifSvzikfABBCIHwsvGbvD+DMJA4A3je8UBQF+Ud52PM2Yh/HoL+tw/jMmUk69yCHQqEAVIEzH52B1q3VjY9p9Ln15B7lYNs2eiO9UDoV9J7oxURhAtacBXiAxHcJyBnphCRdr/WorCxzI1q3hvQvaZT/LMP4whkHVHhSqL1fCzlVwJwxEfs0BnicwChnFmflrQJSSsQ/j0MIAaVDqdVt4WkBwiNqvVw9gR7Ytg397ebN6eZ9w4sD/3YABw609mOzVoah4WvDDENE1LJ4CqwBe379OZ+W3hNC1MLQRphzzuBg9c3FU0YewOfzwZwzUbbKAJznAODv9G/oc+tZWl/8q3h9GUomlE4F+ts6et7twURhAr0nerf8bdC6NSQuJpCoJjB2dwwD3wwgczsDr8eLyr8qUP0q5LSE9w1v7TSKnJZQVRWiQ0BOSahvqrW52uS081wIgcmXk3Vhp2yVoR5yPkfNw/nQiKjVMQDtMbXTOcibf5rQoTvzlJXL6OnqgbfDC8B5DgClUmlDn1vPUk/O0JUh9AReLSc8TnjIP8pjojABTdOQvplG+Hh4e/OleYC+U31I/5ZGqVRCpVKpnaqSL2VdkJFSvgpDUtbGVK18bs1ZtUAIAOOPx6F3N6/3BwAqf1WcHr8W33s22wukH9FhnDWcMXCLPXfrnfolItrveApsly0dKCeLk85l7UdDEB0CmdsZyCmJ1PUUbNtG5GQEwQ+CAIBbd25BTklkbr26QqrR59YTDAYhhED2rjO+KHExAeOsAbtqw563cfm/LiMUDGHoyhAqf1UwcnVkzTKvZ+zOGBLfJeoOgrkHOaAK6N06SqVSLVAVp4q18T6AM7BZP6yv+d7y50qnAjnjlMGas5C5nYF2mINx94p+RMfQlSH8U/4Tk88mMfD1AAdDE1FbYABqQFXXv4S80Xt1PED0wyjkS4nU1RQURUHqWgoAYJwzkHuYw+CFQYSPhaEeVBE/H4eckui/0F8b92JX7YafW7eMfhXJS0nIWQnjnIHyXNm5KksIpH5JoVwuI34+DtWvIvZpDNn7WWf8zooyA0Dvh70oPC3UrT9yMgKfz+fc/6cviujpKLIPshi6MgTRIaBp2qsB0i9lXc9NXQ/QyveWPY+edK6wM85ljwSyAAAC70lEQVQaGPl5BEII9Ly7fq8XbR9DDxG5wYGFhYWFpSdyWrZfQ7fYTZ+5k+Fl0y2u+LyIxMUERn8fbdrpp8ztDGIfxdruFNiq01sbsbhv9ZxPQ/jbrN3YILskMXHVaIvvA5EbLM853GVpX0v9ksLE4wkAzi0Hkj8k+a3dIf6DfkRPRTFwgT08ROQ+PJTQvhb/Ig580exStCdzZnemcCEiagUcA0RERESuwwBERERErsMARERERK7jmgDk6/A5c0sRbZFlWfB1+F6/IBER7XuuCUCqqsKc5aBP2jpz1tz4/Z+IiGhfa/8A5HEefr8fckai+LzIniDaFMuyUHxehJyR8Pv9te8UERG1Llc048Ij4FN80HUdpmlCPpIoz5ebXSxqEb4OnzN5rK7Dp/hqc6kREVHrckUAggcQHQIqVPg6fKhoFaDa7EJRy/AAXo8XQghnFnp37DVERG3NNU25EALCI5x5tarbmPGc3Mnj9CS6Z4/ZOKVDwK7CfXVTdbadiFqTu5qspYMYe39os9y1p2xKj64iV7QgOtz1w8K2LYQOc1A8UatyZ7Puzq0m2lmLg8GNYzryxRzseUAIpf33r6oTfgQqMI4HOSieqEVxtyWiLRMeAa3Th/TnIaQfSky8NGHN280u1q5SOgRCh1UYxwLQOjkonqhVMQAR0dYtXmCg+VUkTvlQqbrgAgMOiidqC9x1iWhbXHmBAQfFE7U87r5EtH1uu8CALSdRy+NuTEQ7hy0KEbWI9p8Kg4iIiGgFBiAiIiJyHQYgIiIich0GICIiInIdBiAiIiJyHQYgIiIich0GICIiInIdBiAiIiJynboA5PV43XMnVyIiInKP6mLOWVQXgIQQsOatPS8TERER0W6y5i0IIWrPVwUge96GZVnsCSIiIqLWVwUsy4I9b9cFoAMLCwsLyxeybbv2qFQrzSgqERER0Y7werwQQtQeS3MW1gcgwAlBVbsJRSQiIiLaHcIj6iZsXh2AiIiIiNrc/wewUSbctvb5bgAAAABJRU5ErkJggg=="},468:function(e,t,a){e.exports=a.p+"assets/img/actions-1.a647260e.jpg"},469:function(e,t,a){e.exports=a.p+"assets/img/actions-2.961474aa.jpg"},470:function(e,t,a){e.exports=a.p+"assets/img/actions-3.f369fd0c.jpg"},471:function(e,t,a){e.exports=a.p+"assets/img/variables-1.ef01834f.jpg"},472:function(e,t,a){e.exports=a.p+"assets/img/variables-2.29ab7418.jpg"},473:function(e,t,a){e.exports=a.p+"assets/img/file-upload-1.18599992.jpg"},474:function(e,t,a){e.exports=a.p+"assets/img/file-upload-2.9999a2fb.jpg"},475:function(e,t,a){e.exports=a.p+"assets/img/file-upload-3.43a9e10c.jpg"},516:function(e,t,a){"use strict";a.r(t);var i=a(65),s=Object(i.a)({},(function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[i("h1",{attrs:{id:"symbol-management"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#symbol-management"}},[e._v("#")]),e._v(" Symbol management")]),e._v(" "),i("p",[e._v("The modelling of input symbols is a key aspect of using ALEX.\nThey define interactions with the system under learning and thus are the building blocks of every learning process and test case.")]),e._v(" "),i("p",[i("img",{attrs:{src:a(460),alt:"Symbols"}})]),e._v(" "),i("p",[e._v("Once you have logged in and opened a project, click on "),i("span",{staticClass:"label"},[e._v("1")]),e._v(" to open the view for the symbol management.")]),e._v(" "),i("h2",{attrs:{id:"symbol-groups"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#symbol-groups"}},[e._v("#")]),e._v(" Symbol groups")]),e._v(" "),i("p",[e._v("Symbol groups are logical container for symbols.\nPer default, there is a default group that is created during the creation of the project.\nThe default group can not be deleted, and all symbols, if not specified otherwise, are put into it.\nYou can create a new group by clicking on "),i("span",{staticClass:"label"},[e._v("2")]),e._v(" and select the corresponding item from the dropdown menu.\nYou are then asked for a name for the group, which has to be unique.\nOnce a group has been created, you can edit and delete it, by clicking on the "),i("em",[e._v("gear")]),e._v(" icon that is found on the right.")]),e._v(" "),i("h2",{attrs:{id:"symbols"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#symbols"}},[e._v("#")]),e._v(" Symbols")]),e._v(" "),i("p",[e._v("When creating a new symbol (see "),i("span",{staticClass:"label"},[e._v("2")]),e._v("), you have to specify two properties:")]),e._v(" "),i("table",[i("thead",[i("tr",[i("th",[e._v("Name")]),e._v(" "),i("th",[e._v("Description")])])]),e._v(" "),i("tbody",[i("tr",[i("td",[e._v("Name")]),e._v(" "),i("td",[e._v("A unique name of the symbol")])]),e._v(" "),i("tr",[i("td",[e._v("Description")]),e._v(" "),i("td",[e._v("A textual description of the symbol (optional)")])]),e._v(" "),i("tr",[i("td",[e._v("Expected result")]),e._v(" "),i("td",[e._v("A textual description of the expected result (optional)")])]),e._v(" "),i("tr",[i("td",[e._v("Symbol group")]),e._v(" "),i("td",[e._v("The group the symbol belongs to. Per default, the default group of the project is used.")])])])]),e._v(" "),i("p",[e._v("Once the symbol has been created successfully, it appears in the specified group.\nFor each symbol, there is a list of operations that are accessible by clicking on the menu "),i("span",{staticClass:"label"},[e._v("3")]),e._v(" of which most are self explanatory.\nIn the menu on top of the page, these operations are available for a batch of symbols.")]),e._v(" "),i("p",[e._v("Each symbol contains of a sequence of actions, that are managed in a separate view.\nClick on the link below the symbol name or the item "),i("em",[e._v("Actions")]),e._v(" in menu "),i("span",{staticClass:"label"},[e._v("3")]),e._v(" to open the action management for the symbol.")]),e._v(" "),i("h3",{attrs:{id:"searching-symbols"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#searching-symbols"}},[e._v("#")]),e._v(" Searching symbols")]),e._v(" "),i("p",[i("img",{attrs:{src:a(461),alt:"Search"}})]),e._v(" "),i("p",[e._v("Directly below the action bar, a search input is displayed which you can use to quickly find symbols.\nA click on a result redirects you to the symbol page.")]),e._v(" "),i("h3",{attrs:{id:"restoring-archived-symbols"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#restoring-archived-symbols"}},[e._v("#")]),e._v(" Restoring archived symbols")]),e._v(" "),i("p",[e._v("Once you archived a symbol, it is not really removed from the database, instead, they are put into the symbol archive.")]),e._v(" "),i("p",[i("img",{attrs:{src:a(462),alt:"Symbols trash bin"}})]),e._v(" "),i("p",[e._v("You can see all archived symbols in the overview which can be accessed via the item "),i("em",[e._v("Archive")]),e._v(" in the sidebar.\nHere, you can recover symbols, edit their names and permanently delete them.\nNote that it is only possible to delete a symbol permanently if the symbol is not still in use, for example in test reports or learning results.\nFurther, recovered symbol is then moved into the default group.")]),e._v(" "),i("h3",{attrs:{id:"permanently-delete-symbols"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#permanently-delete-symbols"}},[e._v("#")]),e._v(" Permanently delete symbols")]),e._v(" "),i("p",[e._v("Symbols can be deleted permanently from the archive if there are no references to the symbol anymore, be it for example in models, tests or other symbols.")]),e._v(" "),i("ol",[i("li",[e._v("In the sidebar, click on "),i("strong",[e._v("Symbols > Archive")])]),e._v(" "),i("li",[e._v("Select the symbols you want to have deleted permanently")]),e._v(" "),i("li",[e._v("In the action bar, click on the "),i("strong",[e._v("Delete")]),e._v("-button")]),e._v(" "),i("li",[e._v("If there is a reference to one of the selected symbols, a notification will appear.\nOtherwise the symbols are removed.")])]),e._v(" "),i("h3",{attrs:{id:"export-import"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#export-import"}},[e._v("#")]),e._v(" Export & import")]),e._v(" "),i("p",[e._v("If you want to save a set of symbols for another project or use existing ones, ALEX offers an export and import feature.\nNote that existing symbol groups are not exported in order to be compatible with other projects.")]),e._v(" "),i("p",[i("img",{attrs:{src:a(463),alt:"Export"}})]),e._v(" "),i("p",[e._v("In order to export symbols, select the corresponding symbols in the overview and click on the export button "),i("span",{staticClass:"label"},[e._v("1")]),e._v(".\nYou are then asked for name of the JSON file which will be downloaded.\nAdditionally, you can decide if only the selected symbols are exported, or if the symbol groups that they are in are exported as well.")]),e._v(" "),i("p",[i("img",{attrs:{src:a(464),alt:"Import 1"}})]),e._v(" "),i("p",[e._v("In the same view, you can import existing symbols from a JSON file by clicking on "),i("span",{staticClass:"label"},[e._v("2")]),e._v(" which opens a modal window.\nHere, drag and drop the JSON file you exported in the previous step.\nThe import will not work unless the names of the symbols are unique within the project.\nIf everything goes fine, the modal window will close automatically and the symbols appear in the selected group.")]),e._v(" "),i("h3",{attrs:{id:"symbol-parameters"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#symbol-parameters"}},[e._v("#")]),e._v(" Symbol parameters")]),e._v(" "),i("p",[i("img",{attrs:{src:a(465),alt:"Parameters"}})]),e._v(" "),i("p",[e._v("Symbols have input and output parameters for variables and counters (see next section for more information).")]),e._v(" "),i("p",[i("img",{attrs:{src:a(466),alt:"Parameters"}})]),e._v(" "),i("p",[e._v("Variables and counters are read from and written into and a global store during a membership query, see the image above.\nBefore a variable or counter can be used in a symbol, it has to be defined in as input parameter for the symbol.\nLocal modifications of variables and counters do not affect the global context unless they are written back as output.")]),e._v(" "),i("figure",[i("img",{attrs:{src:a(467)}})]),e._v(" "),i("p",[e._v("If you use a variable or a counter that has not been defined, the execution of the symbols fails and the output is: "),i("em",[e._v("Undefined variable: Name")]),e._v(", or "),i("em",[e._v("Undefined counter: Name")]),e._v(" respectively.")]),e._v(" "),i("h2",{attrs:{id:"actions"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#actions"}},[e._v("#")]),e._v(" Actions")]),e._v(" "),i("p",[e._v("The function of a symbol is defined by its actions and their execution order.\nAn action can be understood as an atomic interaction with a system, like clicking on a button, submitting a form, making an HTTP request to a REST API and so on.")]),e._v(" "),i("p",[i("img",{attrs:{src:a(468),alt:"Actions"}})]),e._v(" "),i("p",[e._v("In the actions view of a symbol, the sequence of actions, which can be rearranged via drag and drop, is displayed.\nEverything you do here is not saved automatically.\nInstead, a notification on the top "),i("span",{staticClass:"label"},[e._v("3")]),e._v(" notifies you that something has changed.\nA click on the "),i("em",[e._v("Save")]),e._v(" button saves the action and you are safe to navigate to another page.")]),e._v(" "),i("p",[i("img",{attrs:{src:a(469),alt:"Actions"}})]),e._v(" "),i("p",[e._v("A click on the create button opens a modal window, where, on the left, the list of all possible actions is listed.\nOn the right, the form for a selected action is displayed.\nWith "),i("span",{staticClass:"label"},[e._v("4")]),e._v(" you can search for an action by its name instead of searching it in the list.")]),e._v(" "),i("p",[e._v("Each action can be marked with three different flags which are")]),e._v(" "),i("table",[i("thead",[i("tr",[i("th",[e._v("Flag")]),e._v(" "),i("th",[e._v("Description")])])]),e._v(" "),i("tbody",[i("tr",[i("td",[e._v("negated")]),e._v(" "),i("td",[e._v("Negates the outcome of an action.")])]),e._v(" "),i("tr",[i("td",[e._v("ignoreFailure")]),e._v(" "),i("td",[e._v('If this flag is set to "true" proceeding actions are executed although the action failed.')])]),e._v(" "),i("tr",[i("td",[e._v("disabled")]),e._v(" "),i("td",[e._v('If this flag is set to "true" its execution is skipped during the call of its symbol. '),i("span",{staticClass:"label"},[e._v("2")])])])])]),e._v(" "),i("p",[e._v("Normally, the output of a system is either "),i("em",[e._v('"Ok"')]),e._v(" or "),i("em",[e._v('"Failed"')]),e._v(" depending on success of the execution of the symbol.\nIf this is not expressive enough, you can also specify a custom failure output of each action that is propagated to the symbol.\nInsert the custom output in "),i("span",{staticClass:"label"},[e._v("6")]),e._v(" (image above).\nIn this field, dynamic values can be inserted as well (see section about variables and counters below).")]),e._v(" "),i("p",[e._v("In the overview, you see another input field for the custom success output of the symbol.\nThe value that is inserted here will be the output in case all actions can be executed successfully.\nNote that there can be dynamic outputs as well via variables and counters (see below).")]),e._v(" "),i("p",[i("img",{attrs:{src:a(470),alt:"Actions"}})]),e._v(" "),i("p",[e._v("A useful feature is that you can also use copy, cut and paste operations on actions, if e.g. symbols behave similar.\nThe option for this can be found in the dropdown menu on the right of each action or for a batch operation on selection actions in the action bar on top "),i("span",{staticClass:"label"},[e._v("7")]),e._v(".")]),e._v(" "),i("p",[e._v("In the next sections, we go a little deeper into the single categories of actions.")]),e._v(" "),i("h3",{attrs:{id:"web-actions"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#web-actions"}},[e._v("#")]),e._v(" Web actions")]),e._v(" "),i("p",[e._v("Web actions are used to interact with a browser interface like a normal user would and are based on the Selenium framework.\nMost web actions require that a "),i("em",[e._v("locator")]),e._v(" to the element to interact with is specified.\nThere are three possible options how to define such a locator:")]),e._v(" "),i("p",[e._v("| Type | Description | Example |\n|-------|---------------------------------------------------------------------------------------------------|\n| CSS | A valid CSS3 locator | "),i("code",[e._v("#new-todo")]),e._v(" |\n| XPath | An XPath expression to an element in the DOM tree | "),i("code",[e._v("//*[@id='new-todo']")]),e._v(" |\n| JS | A JavaScript snippet that returns an element, e.g. | "),i("code",[e._v("return document.querySelector('#new-todo')")]),e._v(" |")]),e._v(" "),i("h3",{attrs:{id:"rest-actions"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#rest-actions"}},[e._v("#")]),e._v(" REST actions")]),e._v(" "),i("p",[e._v("REST actions are used to communicate with HTTP-based APIs and offer the possibility to perform HTTP requests and assert the contents of HTTP responses.\nMost REST actions assume that the response body is formatted in JSON.")]),e._v(" "),i("p",[e._v("Working with HTTP requests and responses follows a certain pattern.\nWhen modeling symbols, start with a "),i("em",[e._v("Make Request")]),e._v(" action and use other actions to work with the response.\nThe context of the "),i("em",[e._v("Make Request")]),e._v(" action, namely the HTTP response, is passed to the following actions until the next "),i("em",[e._v("Make Request")]),e._v(" action is made.")]),e._v(" "),i("h3",{attrs:{id:"general-actions"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#general-actions"}},[e._v("#")]),e._v(" General actions")]),e._v(" "),i("p",[e._v("Actions of this group allow the interaction between different symbols and actions, for example by storing and passing "),i("em",[e._v("String")]),e._v(" and "),i("em",[e._v("Integer")]),e._v(" values to other actions.\nThis is achieved by using "),i("em",[e._v("Variables")]),e._v(" and "),i("em",[e._v("Counters")]),e._v(" respectively, which are explained later on this page.")]),e._v(" "),i("h3",{attrs:{id:"label-actions"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#label-actions"}},[e._v("#")]),e._v(" Label actions")]),e._v(" "),i("p",[e._v("There are to kinds of actions of this type:")]),e._v(" "),i("p",[e._v("The "),i("strong",[e._v("Create Label")]),e._v(" action is used to define certain points inside the action sequence of a symbol that can be jumped to during the execution.")]),e._v(" "),i("p",[e._v("The "),i("strong",[e._v("Jump to Label")]),e._v(" action can be used to conditionally jump to an existing label "),i("em",[e._v("L")]),e._v(" inside the action sequence.\nIt expects a JavaScript snipped that returns a boolean value.\nIf the script returns "),i("code",[e._v("true")]),e._v(" then execution continues with the action that comes after "),i("em",[e._v("L")]),e._v(".\nOtherwise the action sequence is continued normally.")]),e._v(" "),i("p",[e._v("Both actions will never return a failed output.")]),e._v(" "),i("h2",{attrs:{id:"variables-and-counters"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#variables-and-counters"}},[e._v("#")]),e._v(" Variables and counters")]),e._v(" "),i("p",[e._v("Many web applications handle dynamic data.\nIn order to model and learn such behaviors and to pass data between symbols, actions and learn processes, "),i("em",[e._v("variables")]),e._v(" and "),i("em",[e._v("counters")]),e._v(".")]),e._v(" "),i("definition",{attrs:{term:"Variable"}},[e._v("\n A variable is a string value that is kept in the scope of a membership query.\n")]),e._v(" "),i("definition",{attrs:{term:"Counter"}},[e._v("\n A counter is a positive or negative integer value that are persisted in the database per project.\n Usually, they are used to create multiple objects of the same kind, e.g. user1, user2, ... and so on. \n")]),e._v(" "),i("p",[e._v("In order to make use of those in actions, there is a template language that has to be used in action fields:")]),e._v(" "),i("div",{pre:!0},[i("table",[i("thead",[i("tr",[i("th",[e._v("Notation")]),e._v(" "),i("th",[e._v("Description")])])]),e._v(" "),i("tbody",[i("tr",[i("td",[e._v("{{#counterName}}")]),e._v(" "),i("td",[e._v("The value of the counter with the name "),i("em",[e._v("counterName")]),e._v(" is inserted")])]),e._v(" "),i("tr",[i("td",[e._v("{{$variableName}}")]),e._v(" "),i("td",[e._v("The value of the variable with the name "),i("em",[e._v("variableName")]),e._v(" is inserted")])]),e._v(" "),i("tr",[i("td",[e._v("{{:variableName}}")]),e._v(" "),i("td",[e._v("The value of the environment variable with the name "),i("em",[e._v("variableName")]),e._v(" is inserted")])])])])]),i("p",[e._v("The following example demonstrates the usage of variables, but counters can be used similarly.")]),e._v(" "),i("p",[i("img",{attrs:{src:a(471),alt:"Variables 1"}})]),e._v(" "),i("p",[e._v("Assume that we have an application that manages todo items and the element with the selector "),i("code",[e._v("#new-todo")]),e._v(" is the input field that allows a user to create a new item.\nWe now want to insert the content of the item dynamically via a variable.\nFirst, create an action that sets the value of the variable.\nAs you can see in the picture above, there are some choices for how to do this.")]),e._v(" "),i("p",[i("img",{attrs:{src:a(472),alt:"Variables 2"}})]),e._v(" "),i("p",[e._v("Then, we create another action that inserts the value of the variable into the element "),i("code",[e._v("#new-todo")]),e._v(".\nIn the input field for the value, we use the notation from the table above to indicate that we want to insert the value of the variable "),i("em",[e._v("todoName")]),e._v(".")]),e._v(" "),i("p",[e._v("As soon as the action is executed, the value of "),i("em",[e._v("todoName")]),e._v(" is inserted automatically.\nIn the todo list, a todo with the text "),i("em",[e._v('"buy milk"')]),e._v(" would appear in the application.")]),e._v(" "),i("h2",{attrs:{id:"using-files"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#using-files"}},[e._v("#")]),e._v(" Using files")]),e._v(" "),i("h3",{attrs:{id:"upload"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#upload"}},[e._v("#")]),e._v(" Upload")]),e._v(" "),i("p",[e._v("A special functionality we want to present here is the upload of files to the target application via an action, since there is no dedicated action for that.\nFor this to work, two requirements have to be met:")]),e._v(" "),i("ol",[i("li",[e._v("All files have to be uploaded into ALEX first.")]),e._v(" "),i("li",[e._v("The file upload only works with native "),i("code",[e._v('')]),e._v(" elements.")]),e._v(" "),i("li",[e._v("The execution of JavaScript has the be enabled by the targeted web driver.")])]),e._v(" "),i("p",[i("img",{attrs:{src:a(473),alt:"Files 1"}})]),e._v(" "),i("p",[e._v("For uploading files into ALEX, navigate to the "),i("em",[e._v("files")]),e._v(" page by clicking on the corresponding item in the sidebar "),i("span",{staticClass:"label"},[e._v("1")]),e._v(".\nThen click on "),i("span",{staticClass:"label"},[e._v("2")]),e._v(" to open a native file choosing dialog or drag and drop files directly in that element.")]),e._v(" "),i("p",[i("img",{attrs:{src:a(474),alt:"Files 2"}})]),e._v(" "),i("p",[e._v("Then, click on the upload button "),i("span",{staticClass:"label"},[e._v("3")]),e._v(" to start the upload.\nThe progress indicator indicates how much of a file has already been uploaded.")]),e._v(" "),i("p",[i("img",{attrs:{src:a(475),alt:"Files 3"}})]),e._v(" "),i("p",[e._v("Once the upload is completed, the files are displayed in a list.\nThen, use the "),i("strong",[e._v("Upload File")]),e._v(" action and specify a file to upload and an "),i("code",[e._v('input[type="file""]')]),e._v(" element.\nNote that currently, it is not possible to upload multiple files at once.")]),e._v(" "),i("h3",{attrs:{id:"download"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#download"}},[e._v("#")]),e._v(" Download")]),e._v(" "),i("p",[e._v("Once you have uploaded a file, you can also download it again.\nTherefore, click on the corresponding menu item in the dropdown menu of a file.")])],1)}),[],!1,null,null,null);t.default=s.exports}}]); \ No newline at end of file diff --git a/book/assets/js/5.f6cc4de1.js b/book/assets/js/5.f6cc4de1.js new file mode 100644 index 000000000..8dca53e64 --- /dev/null +++ b/book/assets/js/5.f6cc4de1.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{396:function(t,e,i){var n=i(0),s=i(44),l=i(4),r=i(67),c=i(69),u=i(204),d=/MSIE .\./.test(r),o=n.Function,a=function(t){return d?function(e,i){var n=u(arguments.length,1)>2,r=l(e)?e:o(e),d=n?c(arguments,2):void 0;return t(n?function(){s(r,this,d)}:r,i)}:t};t.exports={setTimeout:a(n.setTimeout),setInterval:a(n.setInterval)}},397:function(t,e,i){},484:function(t,e,i){i(485),i(486)},485:function(t,e,i){var n=i(1),s=i(0),l=i(396).setInterval;n({global:!0,bind:!0,forced:s.setInterval!==l},{setInterval:l})},486:function(t,e,i){var n=i(1),s=i(0),l=i(396).setTimeout;n({global:!0,bind:!0,forced:s.setTimeout!==l},{setTimeout:l})},487:function(t,e,i){"use strict";i(397)},495:function(t,e,i){"use strict";i.r(e);i(484),i(96),i(9),i(97);var n={name:"Slides",data:function(){return{slides:[],currentSlide:0}},mounted:function(){var t=this;this.$nextTick((function(){setTimeout((function(){return t.loadSlides()}),0)}))},methods:{loadSlides:function(){var t=this;this.$el.querySelectorAll(".slide").forEach((function(e){t.slides.push({src:e.querySelector(".image img").getAttribute("data-src"),title:e.querySelector(".image img").getAttribute("data-title"),content:e.querySelector(".text").innerHTML})}))},previousSlide:function(){this.currentSlide=Math.max(0,this.currentSlide-1)},nextSlide:function(){this.currentSlide=Math.min(this.slides.length-1,this.currentSlide+1)}}},s=(i(487),i(65)),l=Object(s.a)(n,(function(){var t=this,e=t.$createElement,i=t._self._c||e;return i("div",{staticClass:"slides"},[t._t("default"),t._v(" "),i("div",{staticClass:"slide-image"},[t.slides.length>0?i("img",{attrs:{src:t.slides[t.currentSlide].src}}):t._e()]),t._v(" "),t.slides.length>0?i("div",{staticClass:"slide-content"},[null!=t.slides[t.currentSlide].title?i("h4",{staticClass:"slide-title"},[t._v(t._s(t.slides[t.currentSlide].title))]):t._e(),t._v(" "),i("div",{domProps:{innerHTML:t._s(t.slides[t.currentSlide].content)}})]):t._e(),t._v(" "),i("div",{staticClass:"slide-navigation"},[i("div",{staticClass:"indicator"},[i("span",[t._v(t._s(t.currentSlide+1)+" / "+t._s(t.slides.length))])]),t._v(" "),i("div",{staticClass:"buttons"},[t.currentSlide>0?i("button",{on:{click:t.previousSlide}},[t._v("« Previous")]):t._e(),t._v(" "),t.currentSlide