Skip to content

Commit

Permalink
docs(e2e-tests): add documentation for test automation (#55)
Browse files Browse the repository at this point in the history
documentation about TestAutomation E2E Tests was added.
why:
E2E Tests were implemented to test the behaviour of API in different scenarios. Documentation includes the following topics:
TestAutomation Summary,
Access Token Retrieval,
Test Data File Setup,
InterfacePartnerHealthCheck
SystemHealthCheck
RegistrationScenarios,
NotificationInitScenario,
ServiceAccountCUDScenario,
CreateAppScenario.
  • Loading branch information
irinamesh committed Aug 17, 2023
1 parent ccc7b38 commit 06005d4
Show file tree
Hide file tree
Showing 11 changed files with 1,230 additions and 0 deletions.
160 changes: 160 additions & 0 deletions developer/Technical Documentation/TestAutomation/01. Summary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# Test Automation Summary

## How to run

E2E Tests can be started manually with the help of the "Test Automation E2E Tests" workflow via GitHub Actions. This
workflow has two parameters: environment and test category. Environment value can be for example "dev" or "int".
Test category defines, which group of tests will be executed. For now the following test categories are implemented:
all, interface health check, portal health check, portal, registration.

## Users for TestAutomation

For successful run of tests following users should exist in the corresponding environment:

* Portal test users for portal tests
* Technical users for Interface Partner Health Checks

## Management of secrets and environment variables

Sensitive data is stored in a separate from the project tree location and isn't checked into source control. Two types
of data are further distinguished: variables and secrets. Variables include such data as urls and non-sensitive, but
domain specific ids as for example NotificationOfferId. Secrets include user names and passwords as well as specific
tokens such as TempMail API token.

For now the following variables are in use (can be found in the project in ```tests/TestRessources.cs```):

| Variable | Value |
|--------------------------|------------------------------------------------------|
| ENVIRONMENT | dev |
| NOTIFICATION_OFFER_ID | UUID_VALUE |
| PORTAL_USER_COMPANY_NAME | PORTAL-COMPANY-FOR-TESTS |
| CLEARING_HOUSE_URL | <https://validation.test.example.org> |
| CLEARING_HOUSE_TOKEN_URL | <https://iam.test.example.org/{endpoint}/token> |
| SD_FACTORY_BASE_URL | <https://sdfactory.{Env}.example.org> |
| WALLET_BASE_URL | <https://managed-identity-wallets.{Env}.example.org> |
| BASE_PORTAL_URL | <https://portal.{Env}.example.org> |
| BASE_CENTRAL_IDP_URL | <https://centralidp.{Env}.example.org> |
| BASE_PORTAL_BACKEND_URL | <https://portal-backend.{Env}.example.org> |
| BPDM_URL | <https://partners-pool.{Env}.example.org> |

where example.org corresponds to the domain in use.

Following secrets are in use (can be found in the project in ```tests/Secrets.cs```):

| Secret |
|-------------------------------------------|
| TEMPMAIL_APIKEY |
| INTERFACE_HEALTH_CHECK_TECH_CLIENT_ID |
| INTERFACE_HEALTH_CHECK_TECH_CLIENT_SECRET |
| CLEARING_HOUSE_CLIENT_ID |
| CLEARING_HOUSE_CLIENT_SECRET |
| PORTAL_USER_NAME |
| PORTAL_USER_PASSWORD |

where TEMPMAIL_APIKEY is a token to call TempMail API, technical client id and secret for interface health check are
used for BPDM, SdFactory and Wallet health checks, client id and secret for clearing house are used for ClearingHouse
health check and portal user name and password are used for the rest of the tests.

Secrets and variables can be managed via GitHub Actions to run the workflow or locally for local run.

* via GitHub Actions

In order to run workflow "TestAutomation E2E Tests" secrets (user names and passwords) should be added to GitHub Secrets
on environment level. For example, to run on "dev" environment "dev" should be created first and then all necessary
secrets should be added to this environment. Url variables can be added as variables on repository level as they are
parametrized with {Env}. Environment specific variables such as company names and offer ids can be added on environment
level.

* for local test run

In order to set environment variables locally, values should be added into ```tests/appsettings.EndToEndTests.json```.
Secrets should be managed with the help of
the [Secret Manager](https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-7.0&tabs=windows).
First Secret Manager should be initialized in the project with ```dotnet user-secrets init``` and then all necessary
secrets should be set with the help of the command ```dotnet user-secrets set "USER_SECRET" "12345".

## Structure

E2E Tests are divided into two groups: tests for health check and functional tests. Below you can find a short
description of these tests. Detailed information is available in separate files with according names.

Base url for tests:

```
https://portal-backend.{env}.demo.example.org
```

where "env" defines environment specifics.

### Health Check Tests

Health check is needed to be executed to make sure that the appropriate endpoints are available and return a non-empty
response. It can be run separately or before functional tests.

#### [PortalHealthCheck](04.%20PortalHealthCheck.md)

Portal health check is implemented for administration and registration services in order to check the load of static
data and availability of additional endpoints.

#### [InterfacePartnerHealthCheck](03.%20InterfacePArtnerHealthCheck.md)

Interface Partner Health Check is now implemented for BPDM, ClearingHouse, SdFactory and Wallet.

### Functional E2E Tests

Functional E2E tests are designed to check the behavior of an application under different scenarios. Following scenarios
were implemented:

#### [Registration scenarios](05.%20RegistrationScenarios.md)

Registration scenarios suppose to check if registration process runs as expected. The following scenarios were
implemented completely: registration without bpn, update of company detail data after confirmation, in-registration
invitation. Two scenarios (registration without bpn and registration without document upload) were partly implemented as
adjustments in productive code are needed.
Some additional scenarios can be added later. For example, validation of the right company detail data depending on the
selected country.

#### [Notification initial scenario](NotificationInitSceanrio.md)

Notification initial scenario checks if a new random portal role can be assigned and unassigned and if appropriate
notification, to the respective right person and with the correct content is created.

#### [Service Account CUD Scenarios](ServiceAccountCUDScenarios.md)

Create-Update-Delete Scenarios suppose to check if new service accounts can be correctly created, updated and deleted.

## Test Parametrization

Some tests are parameterized, which allow to run test scenarios with different data sets in one launch. The test data
files are json files with the lists of data objects. The structure of these files can be
found [here](08.%20TestDataFileSetup.md).

Parameterized tests are marked as Theory. Member data annotation shows which function delivers test data sets for the
test and calls appropriate functions from TestDataHelper class to fetch necessary data from test data file.

Test data file is firstly parsed as a list of dictionary<string, Object> where dictionary key is a string variable that
represents the name of the object. Dictionary value corresponds to the appropriate data type and deserialized to the
object of this type.

Test data file is first deserialized as a list of Dictionary<string, object>, where string variable defines the type of
object.

## ReportPortal

After running the tests, the results can be sent to ReportPortal for better visualization. In order to make it possible
the following secrets should be added to the file ```tests/ReportPortal.config.json```:

| Secret |
|----------------------------------|
| REPORTPORTAL_URL |
| REPORTPORTAL_PROJECT |
| REPORTPORTAL_AUTHENTICATION_UUID |

Similar to the process described above these secrets can be defined as secrets on environment level in GitHub Actions.
They will be automatically added to the config file before build of the solution.

For local run values should be added to the file ```tests/ReportPortal.config.json```, but should not be committed into
source control.

The values of secrets can be found under the profile tab in deployed ReportPortal. The further specifics for running and
configuring the ReportPortal are highlighted [here](10.%20ReportPortal.md).
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
# Access Token Retrieval

While a normal user usually has access to access tokens by being signed in, when testing endpoints in an automated
manner as part of a CI/CD pipeline it is needed to get access token for tests. For existing users, the token can be
retrieved via the authentication flow using the company name, username and password. For new users invited during the
registration process, a temporary email address needed to be created first in order to receive an email with a password.

The implementation of

* [Authentication Flow](#authentication-flow)
* [Use of disposable email addresses](#use-of-disposable-email-addresses)
* [DeveloperMail API](#developermail-api)
* [TempMail API](#tempmail-api)

will be explained now and can be found here:

```
..\tests\endtoend\AuthFlow
```

## Authentication Flow

In order to fetch a user token, the company name, username and password are required. A series of HTTP requests against
the CentralIdp and SharedIdp have to be made in order to exchange the credentials for an access token via auth code
grant.
Additionally, if a new user was created following an E2E test, the password has to be updated. Thus, the authentication
flow consists of a series of 6 and 8 requests for existing users and new users, respectively:

### Authenticate existing and new users: Start

* Start on the CentralIdp Page

```
GET: https://centralidp.{env}.example.org/auth/realms/CX-Central/protocol/openid-connect/auth
```

This request returns an HTML body from which the list of existing companies can be extracted. The response Header "
Set-Cookie" contains 3 cookies which are required for following requests.

* Forward to Login SharedIdp Url

```
GET: https://centralidp.{env}.example.org/auth/realms/CX-Central/broker/{companyNameInUrl}/login?client_id=Cl2-CX-Portal&tab_id={tabId}&session_code={sessionCode}
```

This request returns the header location to a SharedIdp Url. The query parameters are extracted from the chosen company.
The request headers must include the cookies fetched from the previous request.

* Get Login form

```
GET: {sharedIdpUrl from previous request}
```

This request returns an HTML body with the login form from which a SharedIdp Url can be extracted.

* Authenticate User against SharedIdp or forward to update password

```
POST: {sharedIdpUrl from previous request}
```

This request requires a form body which must include the company name, username and password of the user to be
authenticated. It returns the header location to an Url.
This Url can either be a CentralIdp Url for fetching the auth code for login of an existing user or another SharedIdp
Url for updating the password of a new user.

### Authenticate new users only: Update Password

* Forward to Update-Password form SharedIdp Url

```
GET: {sharedIdpUrl from previous request}
```

This request returns an HTML body with the update-password form from which a SharedIdp Url can be extracted. The request
headers must include the cookies fetched from the first request.

* Update user password

```
POST: {sharedIdpUrl from previous request}
```

This request requires a form body which must include the username, old password, new password and the confirmed new
password of the user to be authenticated. It returns the header location to a CentralIdp Url for fetching the auth Url.
From here on, the authentication flow for new users continues to follow the flow for existing users:

### Authenticate existing and new users: End

* Authenticate User against CentralIdp

```
GET: {centralIdpUrl from previous request}
```

This request returns the header location to a CentralIdp Url. The Url includes the auth code. The request headers must
include the cookies fetched from the first request.

* Exchange Auth code for access token

```
POST: https://centralidp.{env}.example.org/auth/realms/CX-Central/protocol/openid-connect/token
```

This request requires a form body which must include the code, grant type, client id and redirect uri. It returns a JSON
object including the user access token.

## Use of disposable email addresses

The registration process consists of an invitation step in which an administrator sends to a user an invitation to join
the Catena-X Portal. To make it possible temporary email services are used.
Per default [DeveloperMail](https://developermail.com/api/v1/) is used as it is a free API with suitable limit on
requests (only more than 25 requests in one second will result a HTTP 429 Too Many Requests response). In case if this
API is not available [TempMail API](https://apilayer.com/marketplace/temp_mail-api) will be used as it is restricted to
500 requests in month and requires registration to get TempMailApiKey to access functionality.

### DeveloperMail API

The base url for requests to DeveloperMail API is:

```
https://developermail.com/api/v1
```

In order to get a username and password for a new user the following steps are executed:

* Generate a random email address

```
PUT: /mailbox
```

This endpoint returns a response that contains a username and an access token of the type "X-MailboxToken" for all other
requests.

* Send invitation to user @ developermail.com (s. [RegistrationScenarios](05.%20RegistrationScenarios.md))

Important: a delay after sending invitation and before checking mailbox is implemented in order to give time for the
emails to reach the mailbox.

* Get existing message ids

```
GET: /mailbox/{username}
```

* Check mailbox with the body consists of the list with the received ids

```
POST: /mailbox/{username}/messages
```

* Find email with password and fetch it

The password is searched in the first paragraph that follows after the paragraph with the text 'Below you
can find your password' in the email whose topic contains "Password required".

* Delete mailbox

```
DELETE: /mailbox/{username}
```

For security reasons the mailbox is deleted after fetching the password.

### TempMail API

Registration is required to use TempMailApi, which can be done [here](https://apilayer.com/marketplace/temp_mail-api)
with any email address you use. TempMailApiKey should be stored secure as GitHub Secret or locally via Secret Manager
and should not be committed to version control.

The base url for requests to TempMail API is:

```
https://api.apilayer.com/temp_mail
```

* Get available domains

```
GET: /domains
```

In contrast to the first option here a random address is not generated, but a list of available domains is requested.
Any username can be chosen, for now "apitestuser" is hardcoded.

* Send invitation to "apitestuser" @ one of available domains (
s. [RegistrationScenarios](05.%20RegistrationScenarios.md))
* Get password message and fetch password

```
GET: /mail/id/{hashedEmailAddress}
```

where email address is hashed with MD5.

Similar to the approach described above the password is searched in the first paragraph of the table that follows after
the paragraph with the text 'Below you can find your password' in the email whose topic contains "Password required".

* Delete password message

```
DELETE: /delete/id/{mailId}
```

Finally the password message is deleted after fetching the password for security reasons.

In both cases after getting the username and password, an authentication flow can be processed to get an access token
for the user.
Loading

0 comments on commit 06005d4

Please sign in to comment.