Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save OpenAPI definition as json, generate client and run tests #969

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2ca31d4
Save OpenAPI definition as json, generate client and run tests
Dec 15, 2023
bb5bb12
Only do OpenAPI definition testing against the backend in test.yml
Jan 22, 2024
8545ee4
Added action to publish generated OpenAPI clients
Jan 22, 2024
0bc02a9
Use publish_openapi_client.yaml pipeline only when PRs are merged
Jan 22, 2024
1652b12
Added missing env variables
Jan 22, 2024
020d3ef
Use Github environment variables for the generators
Jan 23, 2024
9605856
Bump up cache action to v4
Jan 23, 2024
06c3137
Remove env to stop node server after generating the openapi.json file
Jan 23, 2024
ee14776
Use SciCat without elastic-search
Jan 23, 2024
6ed354b
Run node in background
Jan 23, 2024
4b8a341
Open mongodb port
Jan 23, 2024
df050fb
Restructured github test pipeline
Jan 26, 2024
dcb50c1
First version of python-nextgen client tests
Feb 7, 2024
cc0df98
Move OpenAPI client generation for testing into its own step
Feb 8, 2024
6404e25
Replaced domain names with .invalid
Feb 8, 2024
2204911
Always use elastic search for OpenAPI generation
Feb 8, 2024
1732b7c
Disable elastic search for OpenAPI generation
Feb 8, 2024
1a9e19f
Move OpenAPI testing to extra step to only test with ElasticSearch En…
Feb 9, 2024
8d29036
Wait for mongodb
Feb 9, 2024
1544031
Fix docker-compose
Feb 12, 2024
91b3380
Switch to "python-pydantic-v1" generator
Feb 12, 2024
7e94fb9
Fix javascript test workflow
Feb 12, 2024
9828b97
Merge branch 'master' into openapi-workflows
nitrosx Apr 3, 2024
310c25c
Merge branch 'master' into openapi-workflows
nitrosx Jun 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/openapi/javascript-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
packageName: "scicat-openapi-client"
packageUrl: "javascript.package.url"
projectName: "scicat-openapi-client"
disallowAdditionalPropertiesIfNotPresent: false
usePromises: true
2 changes: 2 additions & 0 deletions .github/openapi/python-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
packageName: "scicat_openapi_client"
packageUrl: "python.package.url"
2 changes: 2 additions & 0 deletions .github/openapi/typescript-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
packageName: "scicat-openapi-client"
packageUrl: "typescript.package.url"
102 changes: 102 additions & 0 deletions .github/workflows/publish_openapi_client.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
name: Generate & Publish OpenAPI Client
env:
NODE_VERSION: 18.x

on:
push:
branches:
- master

jobs:
generate-openapi-definition:
name: Generate the OpenAPI definition and cache it
runs-on: ubuntu-latest
steps:
- name: Check out Git repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}

- name: Install dependencies
if: steps.cached-node-modules.outputs.cache-hit != 'true'
run: npm ci

- name: Build
run: npm run build

- name: Cache OpenAPI definition
id: cached-openapi-definition
uses: actions/cache@v4
with:
path: ./
key: openapi.json

- name: Generate OpenAPI definition
env:
EXIT_AFTER_OPENAPI_GENERATION: true
ELASTICSEARCH_ENABLED: false
MONGODB_URI: mongodb://localhost:27017/scicat
EXPRESS_SESSION_SECRET: a_scicat_secret
JWT_SECRET: a_scicat_secret
PORT: 3000
HTTP_MAX_REDIRECTS: 5
HTTP_TIMEOUT: 5000
JWT_EXPIRES_IN: 3600
LOGGING_DISABLED: true
SITE: PSI
PID_PREFIX: PID.SAMPLE.PREFIX
DOI_PREFIX: DOI.SAMPLE.PREFIX
METADATA_KEYS_RETURN_LIMIT: 100
METADATA_PARENT_INSTANCES_RETURN_LIMIT: 100
ADMIN_GROUPS: ingestor
DELETE_GROUPS: ingestor
CREATE_DATASET_GROUPS: ingestor
CREATE_DATASET_WITH_PID_GROUPS: ingestor
CREATE_DATASET_PRIVILEGED_GROUPS: ingestor
ACCESS_GROUPS_STATIC_VALUES: "ess"
PROPOSAL_GROUPS: ingestor
SAMPLE_GROUPS: ""
DATASET_CREATION_VALIDATION_ENABLED: false
MONGODB_COLLECTION: Dataset
MEM_LIMIT: 4G

# Start mongo container and app before starting
run: |
cp CI/ESS/docker-compose.api.yaml docker-compose.yaml
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should create a new docker compose file that starts on mongodb.

cp functionalAccounts.json.test functionalAccounts.json
docker-compose up --build -d
npm run start

generate-and-push:
name: Run install and cache
runs-on: ubuntu-latest
strategy:
matrix:
generator: ${{ toJSON(env.REPOSITORY_VAR) }}
steps:
- name: Restore OpenAPI definition
id: cached-openapi-definition
uses: actions/cache@v4
with:
path: ./
key: openapi.json

# Use the action to generate a client package
# This uses the default path for the openapi document and thus assumes there is an openapi.json in the current workspace.
# https://github.com/openapi-generators/openapitools-generator-action
# https://openapi-generator.tech/docs/generators/
- name: Generate Client
uses: openapi-generators/openapitools-generator-action@v1
with:
generator: ${{ matrix.generator }}
openapi-file: openapi.json
config-file: .github/openapi/${{ matrix.generator }}-config.yml

# Checkout client and force upload changes
- name: Git Push to its client library repository
run: |
cd ${{ matrix.generator }}
/bin/sh ./git_push.sh
ChuckMoe marked this conversation as resolved.
Show resolved Hide resolved
162 changes: 159 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}

- name: Cache node_modules
id: cached-node-modules
uses: actions/cache@v4
Expand Down Expand Up @@ -103,7 +104,7 @@ jobs:

api_tests:
name: API tests with ElasticSearch enabled - ${{ matrix.elasticsearch_enabled }}
needs: [install-and-cache]
needs: [ install-and-cache ]
runs-on: ubuntu-latest

strategy:
Expand Down Expand Up @@ -171,7 +172,162 @@ jobs:

# Start mongo container and app before running api tests
run: |
cp CI/ESS/docker-compose.api.yaml docker-compose.yaml
cp functionalAccounts.json.test functionalAccounts.json
docker-compose up --build -d
docker-compose -f CI/ESS/docker-compose.api.yaml up --build -d
until curl -s -f -o /dev/null "localhost:27017"; do sleep 5; done
npm run test:api

generate_openapi:
name: Generate OpenAPI definition and generate clients
needs: [ install-and-cache ]
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}

- name: Restore node_modules
id: cached-node-modules
uses: actions/cache@v4
with:
path: node_modules
key: node-modules-${{ hashFiles('package-lock.json') }}-${{ env.NODE_VERSION }}

- name: Start backend
env:
EXIT_AFTER_OPENAPI_GENERATION: true
ELASTICSEARCH_ENABLED: no
MONGODB_URI: mongodb://localhost:27017/scicat
EXPRESS_SESSION_SECRET: a_scicat_secret
JWT_SECRET: a_scicat_secret
PORT: 3000
HTTP_MAX_REDIRECTS: 5
HTTP_TIMEOUT: 5000
JWT_EXPIRES_IN: 3600
LOGGING_DISABLED: True
# NOTE: The SITE variable is set to PSI because of the PublishedData test.
# Testing /register endpoint expects to have it as PSI for that specific scenario.
# Old backend was modifying this at runtime but with NestJS we need to investigate little bit more if there is a bit better and more elegant solution.
SITE: PSI
PID_PREFIX: PID.SAMPLE.PREFIX
DOI_PREFIX: DOI.SAMPLE.PREFIX
METADATA_KEYS_RETURN_LIMIT: 100
METADATA_PARENT_INSTANCES_RETURN_LIMIT: 100
ADMIN_GROUPS: admin,ingestor
DELETE_GROUPS: archivemanager
CREATE_DATASET_GROUPS: group1,group2,group3
CREATE_DATASET_WITH_PID_GROUPS: "group2"
CREATE_DATASET_PRIVILEGED_GROUPS: "group3"
ACCESS_GROUPS_STATIC_VALUES: "ess"
PROPOSAL_GROUPS: "proposalingestor"
SAMPLE_GROUPS: ""
DATASET_CREATION_VALIDATION_ENABLED: true
DATASET_CREATION_VALIDATION_REGEX: "^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-4[0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$"
ES_HOST: https://localhost:9200
ES_USERNAME: elastic
ES_PASSWORD: duo-password
MONGODB_COLLECTION: Dataset
ES_MAX_RESULT: 210000
ES_FIELDS_LIMIT: 400000
ES_INDEX: "dataset"
ES_REFRESH: "wait_for"
STACK_VERSION: 8.8.2
CLUSTER_NAME: es-cluster
MEM_LIMIT: 4G

# Start mongo container and app before running api tests
run: |
docker-compose -f CI/ESS/docker-compose.api.yaml up --build -d
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should cretae a new docker compose file that starts only mongodb. We do not use ES for the openapi generation

until curl -s -f -o /dev/null "localhost:27017"; do sleep 5; done
npm run start

- name: Generate openapi client
uses: openapi-generators/openapitools-generator-action@v1
with:
generator: python-pydantic-v1
openapi-file: openapi.json
config-file: .github/openapi/python-config.yml
command-args: "--ignore-file-override openapi/python/test**"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add the option --skip-validate-spec as mentioned in issue 11090


openapi_tests:
name: OpenAPI tests with ElasticSearch enabled
needs: [ generate_openapi ]
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}

- name: Restore node_modules
id: cached-node-modules
uses: actions/cache@v4
with:
path: node_modules
key: node-modules-${{ hashFiles('package-lock.json') }}-${{ env.NODE_VERSION }}

- name: Start backend
env:
ELASTICSEARCH_ENABLED: yes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turn ES off. No need to have it on to test openapi generate libraries

MONGODB_URI: mongodb://localhost:27017/scicat
EXPRESS_SESSION_SECRET: a_scicat_secret
JWT_SECRET: a_scicat_secret
PORT: 3000
HTTP_MAX_REDIRECTS: 5
HTTP_TIMEOUT: 5000
JWT_EXPIRES_IN: 3600
LOGGING_DISABLED: True
# NOTE: The SITE variable is set to PSI because of the PublishedData test.
# Testing /register endpoint expects to have it as PSI for that specific scenario.
# Old backend was modifying this at runtime but with NestJS we need to investigate little bit more if there is a bit better and more elegant solution.
SITE: PSI
PID_PREFIX: PID.SAMPLE.PREFIX
DOI_PREFIX: DOI.SAMPLE.PREFIX
METADATA_KEYS_RETURN_LIMIT: 100
METADATA_PARENT_INSTANCES_RETURN_LIMIT: 100
ADMIN_GROUPS: admin,ingestor
DELETE_GROUPS: archivemanager
CREATE_DATASET_GROUPS: group1,group2,group3
CREATE_DATASET_WITH_PID_GROUPS: "group2"
CREATE_DATASET_PRIVILEGED_GROUPS: "group3"
ACCESS_GROUPS_STATIC_VALUES: "ess"
PROPOSAL_GROUPS: "proposalingestor"
SAMPLE_GROUPS: ""
DATASET_CREATION_VALIDATION_ENABLED: true
DATASET_CREATION_VALIDATION_REGEX: "^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-4[0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$"
ES_HOST: https://localhost:9200
ES_USERNAME: elastic
ES_PASSWORD: duo-password
MONGODB_COLLECTION: Dataset
ES_MAX_RESULT: 210000
ES_FIELDS_LIMIT: 400000
ES_INDEX: "dataset"
ES_REFRESH: "wait_for"
STACK_VERSION: 8.8.2
CLUSTER_NAME: es-cluster
MEM_LIMIT: 4G

# Start mongo container and app before running api tests
run: |
cp functionalAccounts.json.test functionalAccounts.json
docker-compose -f CI/ESS/docker-compose.api.yaml up --build -d
until curl -s -f -o /dev/null "localhost:27017"; do sleep 5; done
npm run start &

- name: Test OpenAPI
run: |
cd openapi/python
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install --upgrade pip
pip install pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
if [ -f test-requirements.txt ]; then pip install -r requirements.txt; fi
pytest
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ loggers.json
# Configs
.env

# OpenAPI
/openapi
openapi.json

# Logs
logs
*.log
Expand Down
11 changes: 11 additions & 0 deletions CI/E2E/docker-compose-mongo.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
version: "3.2"
services:
mongodb:
image: bitnami/mongodb:latest
volumes:
- "mongodb_data:/bitnami"
ports:
- "27017:27017"
volumes:
mongodb_data:
driver: local
37 changes: 37 additions & 0 deletions openapi/python-nextgen/test/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import scicat_openapi_client as soc

configuration = soc.Configuration(
host="http://localhost:3000"
)
api_client = soc.ApiClient(configuration)

users = {
'admin': soc.CredentialsDto(username='admin', password='am2jf70TPNZsSan'),
'ingestor': soc.CredentialsDto(username='ingestor', password='aman'),
'proposalIngestor': soc.CredentialsDto(
username='proposalIngestor',
password='aman'),
'archiveManager': soc.CredentialsDto(
username='archiveManager',
password='aman'),
'user1': soc.CredentialsDto(
username='user2',
password='a609316768619f154ef58db4d847b75e'),
'user2': soc.CredentialsDto(
username='user2',
password='f522d1d715970073a6413474ca0e0f63'),
#
'nouser': soc.CredentialsDto(
username='nouser',
password='f522d1d715970073a6413474ca0e0f63'),
Comment on lines +11 to +26
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we pull the passwords in from configuration or functionalAccounts.json file?

}


def login(api, user: str):
auth_api = soc.AuthApi(api_client)
login_dto = auth_api.auth_controller_login(users[user])
api.api_client.configuration.access_token = login_dto.access_token


def logout(api):
api.api_client.configuration.access_token = ""
Loading
Loading