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

Can't run API test in GitHub Actions #576

Closed
1 of 2 tasks
paulespinosa opened this issue Aug 23, 2023 · 8 comments · Fixed by #605
Closed
1 of 2 tasks

Can't run API test in GitHub Actions #576

paulespinosa opened this issue Aug 23, 2023 · 8 comments · Fixed by #605

Comments

@paulespinosa
Copy link
Member

paulespinosa commented Aug 23, 2023

Overview

The API tests fail when run in a GitHub Action.

Action Items

  • Identify the cause of the errors
  • Design and implement a fix that does not involve adding environment variables to GitHub Environments or Secrets

Resources/Instructions

GitHub workflows do not have AWS credentials or any other environment variables found in the .env file. Try running the tests without a .env on your local machine to check for test failures.

An example of the test failures is shown in Create build-deploy-ec2.yml

============================= test session starts ==============================
platform linux -- Python 3.10.12, pytest-7.3.1, pluggy-1.2.0
cachedir: .tox/py3/.pytest_cache
Using --randomly-seed=587783261
rootdir: /home/runner/work/HomeUniteUs/HomeUniteUs/api
plugins: cov-4.0.0, randomly-3.12.0
collected 17 items

openapi_server/test/test_configs.py ...                                  [ 17%]
openapi_server/test/test_service_provider_controller.py FFFFF            [ 47%]
openapi_server/test/test_service_provider_repository.py .........        [100%]

=================================== FAILURES ===================================
________ TestServiceProviderController.test_get_service_provider_by_id _________

self = <openapi_server.test.test_service_provider_controller.TestServiceProviderController testMethod=test_get_service_provider_by_id>
result = <TestCaseFunction test_get_service_provider_by_id>

    def __call__(self, result=None):
        """
        Does the required setup, doing it here
        means you don't have to call super.setUp
        in subclasses.
        """
        try:
>           self._pre_setup()

.tox/py3/lib/python3.10/site-packages/flask_testing/utils.py:136: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.tox/py3/lib/python3.10/site-packages/flask_testing/utils.py:149: in _pre_setup
    self.app = self.create_app()
openapi_server/test/__init__.py:38: in create_app
    app.add_api('openapi.yaml', pythonic_params=True)
.tox/py3/lib/python3.10/site-packages/connexion/apps/flask_app.py:72: in add_api
    api = super().add_api(specification, **kwargs)
.tox/py3/lib/python3.10/site-packages/connexion/apps/abstract.py:149: in add_api
    api = self.api_cls(specification,
.tox/py3/lib/python3.10/site-packages/connexion/apis/abstract.py:119: in __init__
    self.add_paths()
.tox/py3/lib/python3.10/site-packages/connexion/apis/abstract.py:232: in add_paths
    self._handle_add_operation_error(path, method, sys.exc_info())
.tox/py3/lib/python3.10/site-packages/connexion/apis/abstract.py:244: in _handle_add_operation_error
    raise value.with_traceback(traceback)
.tox/py3/lib/python3.10/site-packages/connexion/apis/abstract.py:222: in add_paths
    self.add_operation(path, method)
.tox/py3/lib/python3.10/site-packages/connexion/apis/abstract.py:175: in add_operation
    operation = make_operation(
.tox/py3/lib/python3.10/site-packages/connexion/operations/__init__.py:16: in make_operation
    return spec.operation_cls.from_spec(spec, *args, **kwargs)
.tox/py3/lib/python3.10/site-packages/connexion/operations/openapi.py:133: in from_spec
    return cls(
.tox/py3/lib/python3.10/site-packages/connexion/operations/openapi.py:80: in __init__
    super().__init__(
.tox/py3/lib/python3.10/site-packages/connexion/operations/abstract.py:101: in __init__
    self._resolution = resolver.resolve(self)
.tox/py3/lib/python3.10/site-packages/connexion/resolver.py:47: in resolve
    return Resolution(self.resolve_function_from_operation_id(operation_id), operation_id)
.tox/py3/lib/python3.10/site-packages/connexion/resolver.py:68: in resolve_function_from_operation_id
    return self.function_resolver(operation_id)
.tox/py3/lib/python3.10/site-packages/connexion/utils.py:116: in get_function_from_name
    module = importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.10.12/x64/lib/python3.10/importlib/__init__.py:126: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
openapi_server/controllers/users_controller.py:5: in <module>
    from openapi_server.controllers.auth_controller import get_token_auth_header
openapi_server/controllers/auth_controller.py:37: in <module>
    userClient = boto3.client('cognito-idp', region_name=COGNITO_REGION, aws_access_key_id = COGNITO_ACCESS_ID, aws_secret_access_key = COGNITO_ACCESS_KEY)
.tox/py3/lib/python3.10/site-packages/boto3/__init__.py:92: in client
    return _get_default_session().client(*args, **kwargs)
.tox/py3/lib/python3.10/site-packages/boto3/session.py:299: in client
    return self._session.create_client(
.tox/py3/lib/python3.10/site-packages/botocore/session.py:948: in create_client
    client = client_creator.create_client(
.tox/py3/lib/python3.10/site-packages/botocore/client.py:123: in create_client
    client_args = self._get_client_args(
.tox/py3/lib/python3.10/site-packages/botocore/client.py:466: in _get_client_args
    return args_creator.get_client_args(
.tox/py3/lib/python3.10/site-packages/botocore/args.py:87: in get_client_args
    final_args = self.compute_client_args(
.tox/py3/lib/python3.10/site-packages/botocore/args.py:183: in compute_client_args
    endpoint_config = self._compute_endpoint_config(
.tox/py3/lib/python3.10/site-packages/botocore/args.py:278: in _compute_endpoint_config
    return self._resolve_endpoint(**resolve_endpoint_kwargs)
.tox/py3/lib/python3.10/site-packages/botocore/args.py:381: in _resolve_endpoint
    return endpoint_bridge.resolve(
.tox/py3/lib/python3.10/site-packages/botocore/client.py:566: in resolve
    resolved = self.endpoint_resolver.construct_endpoint(
.tox/py3/lib/python3.10/site-packages/botocore/regions.py:205: in construct_endpoint
    result = self._endpoint_for_partition(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <botocore.regions.EndpointResolver object at 0x7f00e695e140>
partition = OrderedDict([('defaults', OrderedDict([('hostname', '{service}.{region}.{dnsSuffix}'), ('protocols', ['https']), ('sig...ict([('variants', [OrderedDict([('hostname', 'xray-fips.us-west-2.amazonaws.com'), ('tags', ['fips'])])])]))]))]))]))])
service_name = 'cognito-idp', region_name = None, use_dualstack_endpoint = None
use_fips_endpoint = None, force_partition = False

    def _endpoint_for_partition(
        self,
        partition,
        service_name,
        region_name,
        use_dualstack_endpoint,
        use_fips_endpoint,
        force_partition=False,
    ):
        partition_name = partition["partition"]
        if (
            use_dualstack_endpoint
            and partition_name in self._UNSUPPORTED_DUALSTACK_PARTITIONS
        ):
            error_msg = (
                "Dualstack endpoints are currently not supported"
                " for %s partition" % partition_name
            )
            raise EndpointVariantError(tags=['dualstack'], error_msg=error_msg)
    
        # Get the service from the partition, or an empty template.
        service_data = partition['services'].get(
            service_name, DEFAULT_SERVICE_DATA
        )
        # Use the partition endpoint if no region is supplied.
        if region_name is None:
            if 'partitionEndpoint' in service_data:
                region_name = service_data['partitionEndpoint']
            else:
>               raise NoRegionError()
E               botocore.exceptions.NoRegionError: You must specify a region.

.tox/py3/lib/python3.10/site-packages/botocore/regions.py:253: NoRegionError
@Joshua-Douglas
Copy link
Member

A project plan for this issue is underway.

We need to restructure the project to lazy-load our boto3 client as needed, instead of using the import time initialization. Our current configuration system relies heavily on import-time configurations. We will need to change this behavior in order to properly implement #577 so I am planning on extending the application configuration system to support environment-specific configurations of the application.

Using this approach the boto3 client will be created using real AWS credentials for PRODUCTION and STAGING and DEVELOPMENT environments, but the client will be disabled for TESTING environments.

In the future we will need to mock the boto client, which can be done using the moto client, but for now it is sufficient to throw an NotImplementedException if the testing app tries to access the boto client.

I'll include a draft project plan down below. My plan is to update the PP as my general solution and implementation progresses.

@Joshua-Douglas
Copy link
Member

Joshua-Douglas commented Sep 9, 2023

Deleted PP from this issue, since it was more relevant to issue #530

@paulespinosa
Copy link
Member Author

paulespinosa commented Sep 9, 2023

@Joshua-Douglas good write up. @ju1es has created separate issues to implement a config system. The implementation of this proposed configuration design can close #530 too.

Create Config System #522 - This is where it started and is closed now
Create Config System For Configs at Runtime #530 - Open seem most related to your write up on the config system.
Create Config System For Credentials #529 - Open

@paulespinosa
Copy link
Member Author

We'll have a specific staging environment that's distinct from what we have/will have at dev.homeunite.us.

In the write-up #576 (comment), I called it "deployed test dev" for lack of a better word or description.

I included some information about the dotenv command-line tool. It is currently used to load the DATABASE_URL variable that is stored in the .env file as an environment variable before running the API.

@Joshua-Douglas
Copy link
Member

Thanks for adding that section @paulespinosa! Design is still in draft form, but I should be done (with an implementation for the most important parts) by Monday.

I'm hoping to close #522 & #530 with this issue since these are closely related. It should partially address #529, but not fully since I won't touch the front end app in this issue.

@Joshua-Douglas
Copy link
Member

Hey @paulespinosa - I thought about your comments a bit more and decided that it would be much clearer if we moved the research to #530. Thanks for the heads up on that issue.

@Joshua-Douglas
Copy link
Member

Moved to ice box since this issue depends on #530.

@paulespinosa
Copy link
Member Author

@Joshua-Douglas Sounds good! Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment