Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 5 additions & 2 deletions collectoss/tasks/github/util/github_api_key_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,11 @@ def get_api_keys(self) -> List[str]:
time.sleep(5)
attempts += 1

if self.config_key is not None:
keys += [self.config_key]
if self.config_key is not None: # Leave out None values
if self.config_key.strip(): # Leave out empty strings
keys += [self.config_key]
else:
self.logger.warning("GitHub API key is an empty string. Please, add a valid one.")
Comment on lines -105 to +109

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

hmm i wonder if we could shorten this to

if self.config_key:
(and keep the else block)

AFAIK (needs testing) i think python treats empty strings as falsy

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I tried this approach before the actual nested implementation. The three cases are pinned in the test file ("", " ", None)

The problem is that if self.config_key: would catch None and "", but " " is not falsy, so it gets added . With a flat else, None logs the warning, which test_none_config_key_with_no_db_keys asserts it shouldn't: None just means the variable was never set.

Also tried if self.config_key.strip(). Catches de whitespace but raises an AttributeError on None.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

do you think it would it be better to throw a self.config_key = self.config_key.strip() earlier in the process? then it would collapse the whitespace case into the "" case that is already handled with if self.config_key?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, probably the besst approach.

I'll add

if self.config_key:
   self.config_key = self.config_key.strip()

right after the key is read with self.config_key = self.get_config_key(). Then, this part can end up as:

if self.config_key:
    keys += [self.config_key]
elif self.config_key is not None: # None just means it was never set
    self.logger.warning("GitHub API key is an empty string. Please, add a valid one.")

That elif for None needs to be there so we don't log a warning for a missing token.

Note: self.config_key is also read to filter the config key out of the database keys, so that comparison now will see the normalized value. I think that's an improvement


if len(keys) == 0:
return []
Expand Down
67 changes: 67 additions & 0 deletions tests/test_classes/test_github_api_keys.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# SPDX-License-Identifier: MIT
import pytest
from unittest.mock import Mock, patch

from collectoss.tasks.github.util.github_api_key_handler import GithubApiKeyHandler


github_whitespace_api_keys_list = ["", " "]
github_none_api_key = None
github_valid_api_key = "ghp_1234567890abcdef1234567890abcdef12345678"
github_valid_db_api_key = "ghp_abcdef1234567890abcdef1234567890abcdef12"

def build_handler(config_key, db_keys):
logger = Mock()

with patch("collectoss.tasks.github.util.github_api_key_handler.RedisList"), \
patch.object(GithubApiKeyHandler, "get_config_key", return_value=config_key), \
patch.object(GithubApiKeyHandler, "get_api_keys_from_database", return_value=db_keys), \
patch.object(GithubApiKeyHandler, "is_bad_api_key", return_value=False) as mock_is_bad_api_key:
handler = GithubApiKeyHandler(logger)

return handler, mock_is_bad_api_key, logger

@pytest.mark.unit
class TestConfigKeys:

@pytest.mark.parametrize("github_whitespace_api_key", github_whitespace_api_keys_list)
def test_whitespace_config_key_with_no_db_keys(self, github_whitespace_api_key):
db_keys = []
handler, mock_is_bad_api_key, logger = build_handler(github_whitespace_api_key, db_keys)

assert handler.keys == []
assert mock_is_bad_api_key.call_count == 0
# with no keys left, get_api_keys returns before it reaches redis
handler.redis_key_list.clear.assert_not_called()

Check warning on line 35 in tests/test_classes/test_github_api_keys.py

View workflow job for this annotation

GitHub Actions / runner / pylint

[pylint] reported by reviewdog 🐶 E1101: Method 'clear' has no 'assert_not_called' member (no-member) Raw Output: tests/test_classes/test_github_api_keys.py:35:8: E1101: Method 'clear' has no 'assert_not_called' member (no-member)
handler.redis_key_list.extend.assert_not_called()

Check warning on line 36 in tests/test_classes/test_github_api_keys.py

View workflow job for this annotation

GitHub Actions / runner / pylint

[pylint] reported by reviewdog 🐶 E1101: Method 'extend' has no 'assert_not_called' member (no-member) Raw Output: tests/test_classes/test_github_api_keys.py:36:8: E1101: Method 'extend' has no 'assert_not_called' member (no-member)
logger.warning.assert_called_once()

def test_none_config_key_with_no_db_keys(self):
db_keys = []
handler, mock_is_bad_api_key, logger = build_handler(github_none_api_key, db_keys)

assert handler.keys == []
assert mock_is_bad_api_key.call_count == 0
handler.redis_key_list.clear.assert_not_called()

Check warning on line 45 in tests/test_classes/test_github_api_keys.py

View workflow job for this annotation

GitHub Actions / runner / pylint

[pylint] reported by reviewdog 🐶 E1101: Method 'clear' has no 'assert_not_called' member (no-member) Raw Output: tests/test_classes/test_github_api_keys.py:45:8: E1101: Method 'clear' has no 'assert_not_called' member (no-member)
handler.redis_key_list.extend.assert_not_called()

Check warning on line 46 in tests/test_classes/test_github_api_keys.py

View workflow job for this annotation

GitHub Actions / runner / pylint

[pylint] reported by reviewdog 🐶 E1101: Method 'extend' has no 'assert_not_called' member (no-member) Raw Output: tests/test_classes/test_github_api_keys.py:46:8: E1101: Method 'extend' has no 'assert_not_called' member (no-member)
logger.warning.assert_not_called()

def test_valid_config_key_with_no_db_keys(self):
db_keys = []
handler, mock_is_bad_api_key, logger = build_handler(github_valid_api_key, db_keys)

assert handler.keys == [github_valid_api_key]
assert mock_is_bad_api_key.call_count == 1
handler.redis_key_list.extend.assert_called_once_with([github_valid_api_key])

Check warning on line 55 in tests/test_classes/test_github_api_keys.py

View workflow job for this annotation

GitHub Actions / runner / pylint

[pylint] reported by reviewdog 🐶 E1101: Method 'extend' has no 'assert_called_once_with' member (no-member) Raw Output: tests/test_classes/test_github_api_keys.py:55:8: E1101: Method 'extend' has no 'assert_called_once_with' member (no-member)
logger.warning.assert_not_called()
Comment thread
MoralCode marked this conversation as resolved.

@pytest.mark.parametrize("github_whitespace_api_key", github_whitespace_api_keys_list)
def test_whitespace_config_key_with_db_keys(self, github_whitespace_api_key):
expected_keys = [github_valid_db_api_key]
# get_api_keys appends to the list it gets back, so hand it a copy
handler, mock_is_bad_api_key, logger = build_handler(github_whitespace_api_key, list(expected_keys))

assert handler.keys == expected_keys
assert mock_is_bad_api_key.call_count == 1
handler.redis_key_list.extend.assert_called_once_with(expected_keys)

Check warning on line 66 in tests/test_classes/test_github_api_keys.py

View workflow job for this annotation

GitHub Actions / runner / pylint

[pylint] reported by reviewdog 🐶 E1101: Method 'extend' has no 'assert_called_once_with' member (no-member) Raw Output: tests/test_classes/test_github_api_keys.py:66:8: E1101: Method 'extend' has no 'assert_called_once_with' member (no-member)
logger.warning.assert_called_once()
Loading