diff --git a/.env.example b/.env.example index 026c60a..fc2452a 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,5 @@ -ENV=staging +OPPE_ENV=staging -TEST_API_TOKEN= -TEST_PROJECT_ID= -TEST_CHANNEL_ID= +OPPE_TEST_API_TOKEN= +OPPE_TEST_PROJECT_ID= +OPPE_TEST_CHANNEL_ID= diff --git a/.github/workflows/code-style.yml b/.github/workflows/code-style.yml index 0495ae2..63591ac 100644 --- a/.github/workflows/code-style.yml +++ b/.github/workflows/code-style.yml @@ -37,9 +37,13 @@ jobs: run: mv .env.example .env - name: Change environment variables in .env run: | - sed -i "s/TEST_API_TOKEN=/TEST_API_TOKEN=${{ secrets.TEST_API_TOKEN }}/g" .env - sed -i "s/TEST_PROJECT_ID=/TEST_PROJECT_ID=${{ secrets.TEST_PROJECT_ID }}/g" .env - sed -i "s/TEST_CHANNEL_ID=/TEST_CHANNEL_ID=${{ secrets.TEST_CHANNEL_ID }}/g" .env + sed -i "s/OPPE_TEST_API_TOKEN=/OPPE_TEST_API_TOKEN=${{ secrets.OPPE_TEST_API_TOKEN }}/g" .env + sed -i "s/OPPE_TEST_PROJECT_ID=/OPPE_TEST_PROJECT_ID=${{ secrets.OPPE_TEST_PROJECT_ID }}/g" .env + sed -i "s/OPPE_TEST_CHANNEL_ID=/OPPE_TEST_CHANNEL_ID=${{ secrets.OPPE_TEST_CHANNEL_ID }}/g" .env - name: Run Tests run: | - pytest --disable-pytest-warnings + pytest --disable-pytest-warnings --cov --cov-report=xml --cov-report=term-missing + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v3 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/README.md b/README.md index 3a7ad05..7534acc 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,9 @@ # oppe-for-python +[![codecov](https://codecov.io/gh/kilobyteno/oppe-for-python/graph/badge.svg?token=JKLDG13D1W)](https://codecov.io/gh/kilobyteno/oppe-for-python) +[![PyPI version](https://badge.fury.io/py/oppe.svg)](https://badge.fury.io/py/oppe) +[![Downloads](https://pepy.tech/badge/oppe)](https://pepy.tech/project/oppe) +[![License](https://img.shields.io/github/license/kilobyteno/oppe-for-python)](LICENSE) + An API wrapper for [Oppe](https://oppe.app) written in Python. diff --git a/oppe/config.py b/oppe/config.py index 4522190..b529001 100644 --- a/oppe/config.py +++ b/oppe/config.py @@ -21,7 +21,7 @@ class Config: if os.path.exists(dotenv_path): load_dotenv(dotenv_path) - ENV = os.getenv('ENV') + ENV = os.getenv('OPPE_ENV') if ENV == 'staging': BASE_URL = 'https://staging.oppe.app/api' diff --git a/oppe/oppe.py b/oppe/oppe.py index 5be0d42..7eaaca4 100644 --- a/oppe/oppe.py +++ b/oppe/oppe.py @@ -55,19 +55,24 @@ def event(self, channel_id, title, description=None, emoji=None, data=None): if not validate_uuid(uuid_input=channel_id): raise UuidValidationError(msg='Channel ID must be a valid UUID') - # Make sure data is an object - if not data: - data = {} - # Create payload to send to Oppe payload = { 'channel_id': channel_id, 'title': title, - 'description': description, - 'emoji': emoji, - 'data': json.dumps(data), } + # If description is not None, add it to the payload + if description: + payload['description'] = description + + # If emoji is not None, add it to the payload + if emoji: + payload['emoji'] = emoji + + # If data is not None, add it to the payload + if data: + payload['data'] = json.dumps(data) + # Send request to Oppe response = requests.post(Config.EVENT_URL, data=json.dumps(payload), headers=request_header(api_token=self.api_token)) if response.status_code != 201: diff --git a/requirements-dev.txt b/requirements-dev.txt index 5bcc559..98e7ad9 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -10,3 +10,4 @@ Faker~=19.6.1 pytest~=7.4.0 pytest-cov~=4.1.0 pytest-sugar~=0.9.7 +pytest-mock~=3.11.1 diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py new file mode 100644 index 0000000..4ecb84d --- /dev/null +++ b/tests/test_exceptions.py @@ -0,0 +1,42 @@ +from oppe.exceptions import EventRequestError, OppeError, UuidValidationError + + +def test_default_parameters(): + """ Test default parameters """ + error = OppeError() + assert error.msg == 'Unknown error occurred' + assert error.data is None + + +def test_custom_parameters(): + """ Test custom parameters """ + error = OppeError(msg='Custom error message', data={'key': 'value'}) + assert error.msg == 'Custom error message' + assert error.data == {'key': 'value'} + + +def test_empty_string_message(): + """ Test empty string message """ + error = OppeError('') + assert error.msg == '' + assert error.data is None + + +def test_with_only_msg_attribute(): + """ Test with only msg attribute """ + error = OppeError('Error message') + assert str(error) == 'Error message' + + +def test_subclass_uuid_validation_error(): + """ Test subclass UuidValidationError """ + error = UuidValidationError(msg='Uuid Validation Error') + assert error.msg == 'Uuid Validation Error' + assert error.data is None + + +def test_subclass_event_request_error(): + """ Test subclass EventRequestError """ + error = EventRequestError(msg='Event Request Error') + assert error.msg == 'Event Request Error' + assert error.data is None diff --git a/tests/test_oppe.py b/tests/test_oppe.py index e67756b..018a680 100644 --- a/tests/test_oppe.py +++ b/tests/test_oppe.py @@ -1,9 +1,11 @@ import os +from unittest.mock import Mock +import pytest from dotenv import load_dotenv from faker import Faker -from oppe.exceptions import UuidValidationError +from oppe.exceptions import EventRequestError, UuidValidationError from oppe.oppe import Oppe fake = Faker() @@ -16,62 +18,62 @@ def init_oppe(): """ Initialize Oppe """ - return Oppe(api_token=os.getenv('TEST_API_TOKEN'), project_id=os.getenv('TEST_PROJECT_ID')) + return Oppe(api_token=os.getenv('OPPE_TEST_API_TOKEN'), project_id=os.getenv('OPPE_TEST_PROJECT_ID')) def test_publish_event(): """ Test publish event """ oppe = init_oppe() - response = oppe.event(channel_id=os.getenv('TEST_CHANNEL_ID'), title=fake.domain_word(), description=fake.sentence()) + response = oppe.event(channel_id=os.getenv('OPPE_TEST_CHANNEL_ID'), title=fake.domain_word(), description=fake.sentence()) assert response is True def test_publish_event_with_emoji(): """ Test publish event with emoji """ oppe = init_oppe() - response = oppe.event(channel_id=os.getenv('TEST_CHANNEL_ID'), title=fake.domain_word(), description=fake.sentence(), emoji='👋') + response = oppe.event(channel_id=os.getenv('OPPE_TEST_CHANNEL_ID'), title=fake.domain_word(), description=fake.sentence(), emoji='👋') assert response is True def test_publish_event_with_data(): """ Test publish event with data """ oppe = init_oppe() - response = oppe.event(channel_id=os.getenv('TEST_CHANNEL_ID'), title=fake.domain_word(), description=fake.sentence(), data={'user_id': 1}) + response = oppe.event(channel_id=os.getenv('OPPE_TEST_CHANNEL_ID'), title=fake.domain_word(), description=fake.sentence(), data={'user_id': 1}) assert response is True def test_publish_event_with_emoji_and_data(): """ Test publish event with emoji and data """ oppe = init_oppe() - response = oppe.event(channel_id=os.getenv('TEST_CHANNEL_ID'), title=fake.domain_word(), description=fake.sentence(), emoji='👋', data={'user_id': 1}) + response = oppe.event(channel_id=os.getenv('OPPE_TEST_CHANNEL_ID'), title=fake.domain_word(), description=fake.sentence(), emoji='👋', data={'user_id': 1}) assert response is True def test_publish_event_with_emoji_and_data_and_no_description(): """ Test publish event with emoji and data and no description """ oppe = init_oppe() - response = oppe.event(channel_id=os.getenv('TEST_CHANNEL_ID'), title=fake.domain_word(), emoji='👋', data={'user_id': 1}) + response = oppe.event(channel_id=os.getenv('OPPE_TEST_CHANNEL_ID'), title=fake.domain_word(), emoji='👋', data={'user_id': 1}) assert response is True def test_publish_event_with_emoji_and_no_description(): """ Test publish event with emoji and no description """ oppe = init_oppe() - response = oppe.event(channel_id=os.getenv('TEST_CHANNEL_ID'), title=fake.domain_word(), emoji='👋') + response = oppe.event(channel_id=os.getenv('OPPE_TEST_CHANNEL_ID'), title=fake.domain_word(), emoji='👋') assert response is True def test_publish_event_with_data_and_no_description(): """ Test publish event with data and no description """ oppe = init_oppe() - response = oppe.event(channel_id=os.getenv('TEST_CHANNEL_ID'), title=fake.domain_word(), data={'user_id': 1}) + response = oppe.event(channel_id=os.getenv('OPPE_TEST_CHANNEL_ID'), title=fake.domain_word(), data={'user_id': 1}) assert response is True def test_publish_event_with_no_description(): """ Test publish event with no description """ oppe = init_oppe() - response = oppe.event(channel_id=os.getenv('TEST_CHANNEL_ID'), title=fake.domain_word()) + response = oppe.event(channel_id=os.getenv('OPPE_TEST_CHANNEL_ID'), title=fake.domain_word()) assert response is True @@ -82,3 +84,16 @@ def test_publish_event_with_wrong_channel_id(): oppe.event(channel_id=fake.sha256(), title=fake.domain_word()) except UuidValidationError as e: assert e.msg == 'Channel ID must be a valid UUID' + + +def test_invalid_api_token(mocker): + """ Test invalid api token """ + # Mock the requests.post method to return a non-201 response + mocker.patch('requests.post', return_value=Mock(status_code=401, json=lambda: {'error': 'Unauthorized'})) + + # Create an instance of the Oppe class + oppe = Oppe(api_token='invalid_token', project_id=os.getenv('OPPE_TEST_PROJECT_ID')) + + # Call the event method with valid parameters + with pytest.raises(EventRequestError): + oppe.event(channel_id=os.getenv('OPPE_TEST_CHANNEL_ID'), title=fake.domain_word())