-
Notifications
You must be signed in to change notification settings - Fork 8
Issue 38 - adding unit tests #45
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
Changes from all commits
2c577e7
700139e
2f6a480
a3052e9
4f331d9
582507b
03b620a
b72a66e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,7 +28,6 @@ | |
| db_password = os.getenv("DB_PASSWORD") | ||
|
|
||
| client = None | ||
| db = None | ||
| creds = None | ||
|
|
||
| app = FastAPI() | ||
|
|
@@ -97,11 +96,12 @@ def validate_token_IBM(token, authURL, clientId, clientSecret=Depends(oauth2_sch | |
|
|
||
|
|
||
| client = couchdb.Server(f'http://{db_username}:{db_password}@{db_host}:{db_port}/') | ||
| try: | ||
| db = client.create(db_name) | ||
| except couchdb.PreconditionFailed: | ||
| db = client[db_name] | ||
|
|
||
| def getDb(): | ||
| try: | ||
| return client.create(db_name) | ||
| except couchdb.PreconditionFailed: | ||
| return client[db_name] | ||
|
|
||
| class Flagged(BaseModel): | ||
| _id: Optional[str] | ||
|
|
@@ -140,11 +140,13 @@ def login(form_data: OAuth2PasswordRequestForm = Depends()): | |
|
|
||
| @app.get("/mark") | ||
| def get_marks(user: dict = Depends(validate)): | ||
| db = getDb() | ||
| return list(map(lambda item: dict(item.doc.items()), db.view('_all_docs',include_docs=True))) | ||
|
|
||
|
|
||
| @app.post("/mark") | ||
| def save_mark(item: Flagged, user: dict = Depends(validate)): | ||
| db = getDb() | ||
| item.user_id = user["sub"] | ||
| data = item.dict() | ||
| _id, _ = db.save(data) | ||
|
|
@@ -153,6 +155,7 @@ def save_mark(item: Flagged, user: dict = Depends(validate)): | |
|
|
||
| @app.put("/mark/{_id}") | ||
| def update_mark(_id: str, item: Flagged, user: dict = Depends(validate)): | ||
| db = getDb() | ||
| doc = db[_id] | ||
| doc["category"] = item.category | ||
| db[doc.id] = doc | ||
|
|
@@ -161,6 +164,7 @@ def update_mark(_id: str, item: Flagged, user: dict = Depends(validate)): | |
|
|
||
| @app.delete("/mark") | ||
| def delete_mark(_id: str, user: dict = Depends(validate)): | ||
| db = getDb() | ||
| my_document = db[_id] | ||
| db.delete(my_document) | ||
| return {"status": "success"} | ||
|
|
@@ -207,6 +211,7 @@ def read_categories(): | |
|
|
||
| @app.put("/analyse") | ||
| def analyse_text(text: Text): | ||
| db = getDb() | ||
| res = [] | ||
| for item in db.view('_all_docs',include_docs=True): | ||
| doc = item.doc | ||
|
|
@@ -217,9 +222,10 @@ def analyse_text(text: Text): | |
| @app.put("/check") | ||
| def check_words(text: Text): | ||
| res = [] | ||
| db = getDb() | ||
| for item in db.view('_all_docs',include_docs=True): | ||
| doc = item.doc | ||
| if doc["category"] == "racial slur" and doc["flagged_string"].lower() in text.content.lower(): | ||
| if doc["category"] == "racial-slur" and doc["flagged_string"].lower() in text.content.lower(): | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Previously, this didn't match what was being returned from the read_categories method so the marks saved through template.html weren't recognized by this method
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can take this out if we'd rather have this fixed in a separate change
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree. Separate PR works better. |
||
| res.append({"flag" : doc["flagged_string"], "category" : doc["category"], "info" : doc["info"]}) | ||
|
|
||
| line_by_line = [] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| import requests | ||
| #example api test | ||
|
|
||
| import json | ||
| import sys | ||
| sys.path.append('../../taketwo-webapi') | ||
| sys.path.append('../util') | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm new to python and dependencies so I'm not sure if this is optimal for being able to access adjacent files
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this seems a little odd to me. Please see here on how to load multiple files - https://fastapi.tiangolo.com/it/tutorial/bigger-applications/ Basically, you need empty
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool! I'll update |
||
| from main import app | ||
| from main import validate | ||
| from main import getDb | ||
| from fastapi.testclient import TestClient | ||
| from util.assert_util import comparePayloads | ||
|
|
||
| def override_validate(): | ||
| return {"sub": 'test'} | ||
|
|
||
| app.dependency_overrides[validate] = override_validate | ||
upkarlidder marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| def test_save_mark(): | ||
| url = '/mark' | ||
|
|
||
| # Additional headers. | ||
| headers = {'Content-Type': 'application/json' } | ||
|
|
||
| # Body | ||
| payload = {'user_id': "test", 'flagged_string': "test string", 'category': "stereotyping", 'info': "none", 'url': "example.com"} | ||
|
|
||
| client = TestClient(app) | ||
| # convert dict to json by json.dumps() for body data. | ||
| resp = client.post(url, headers=headers, data=json.dumps(payload,indent=4)) | ||
|
|
||
| # Validate response headers and body contents, e.g. status code. | ||
| assert resp.status_code == 200, "Unexpected status code. Was: " + str(resp.status_code) | ||
| resp_body = resp.json() | ||
| assert resp_body['url'] == 'example.com', "Unexpected url. Was: " + resp_body['url'] | ||
|
|
||
| #make sure payload stored properly | ||
| storedPayload = getDb().get(resp_body["_id"]) | ||
| comparePayloads(payload, storedPayload) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Different from the previous version, add comparison of what's stored in the db to the payload we send to make sure it's stored properly |
||
|
|
||
| # print response full body as text | ||
| print(resp.text) | ||
|
|
||
| if __name__ == '__main__': | ||
| test_save_mark() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
|
|
||
| def comparePayloads(expected: dict, actual: dict): | ||
| assert expected["user_id"] == actual["user_id"], showDiff(str(expected["user_id"]), str(actual["user_id"])) | ||
| assert expected["flagged_string"] == actual["flagged_string"], showDiff(str(expected["flagged_string"]), str(actual["flagged_string"])) | ||
| assert expected["category"] == actual["category"], showDiff(str(expected["category"]), str(actual["category"])) | ||
| assert expected["info"] == actual["info"], showDiff(str(expected["info"]), str(actual["info"])) | ||
| assert expected["url"] == actual["url"], showDiff(str(expected["url"]), str(actual["url"])) | ||
|
|
||
| def showDiff(expected: str, actual: str): | ||
| return "Expected: " + expected + ", Actual: " + actual |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| from json import load | ||
| import sys | ||
| sys.path.append('../../taketwo-webapi') | ||
| sys.path.append('../util') | ||
| import unittest | ||
| from unittest.mock import patch | ||
|
|
||
| from main import analyse_text | ||
| from main import Text | ||
|
|
||
| from util.mock_db_util import getRow | ||
| from util.mock_db_util import setupMocks | ||
|
|
||
| class TestAnalyseText(unittest.TestCase): | ||
upkarlidder marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| @patch('main.getDb') | ||
| def test_multiple_items_with_flagged_string(self, getDbMock): | ||
| firstRow = getRow("bad_string", "the_category", "the_info") | ||
| secondRow = getRow("bad_string_2", "the_category", "the_info") | ||
|
|
||
| setupMocks(getDbMock, [firstRow, secondRow]) | ||
|
|
||
| data = {'content': 'bad_string, bad_string_2'} | ||
| text = Text(**data) | ||
| output = analyse_text(text) | ||
|
|
||
| expected = {"biased": | ||
| [{"flag": "bad_string", "category": "the_category", "info": "the_info"}, | ||
| {"flag": "bad_string_2", "category": "the_category", "info": "the_info"}]} | ||
| assert output == expected, "Actual: " + str(output) + " Expected: " + str(expected) | ||
|
|
||
| @patch('main.getDb') | ||
| def test_single_item_with_flagged_string(self, getDbMock): | ||
| firstRow = getRow("bad_string", "the_category", "the_info") | ||
|
|
||
| setupMocks(getDbMock, [firstRow]) | ||
|
|
||
| data = {'content': 'bad_string'} | ||
| text = Text(**data) | ||
| output = analyse_text(text) | ||
|
|
||
| expected = {"biased": | ||
| [{"flag": "bad_string", "category": "the_category", "info": "the_info"}]} | ||
| assert output == expected, "Actual: " + str(output) + " Expected: " + str(expected) | ||
|
|
||
| @patch('main.getDb') | ||
| def test_no_text_provided(self, getDbMock): | ||
| firstRow = getRow("bad_string", "the_category", "the_info") | ||
|
|
||
| setupMocks(getDbMock, [firstRow]) | ||
|
|
||
| data = {'content': ''} | ||
| text = Text(**data) | ||
| output = analyse_text(text) | ||
|
|
||
| expected = {"biased": []} | ||
| assert output == expected, "Actual: " + str(output) + " Expected: " + str(expected) | ||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| from json import load | ||
| import sys | ||
| sys.path.append('../../taketwo-webapi') | ||
| sys.path.append('../util') | ||
| import unittest | ||
| from unittest.mock import patch | ||
|
|
||
| from main import check_words | ||
| from main import Text | ||
|
|
||
| from util.mock_db_util import getRow | ||
| from util.mock_db_util import setupMocks | ||
|
|
||
| class TestCheckWords(unittest.TestCase): | ||
|
|
||
| @patch('main.getDb') | ||
| def test_no_text_provided(self, getDbMock): | ||
| firstRow = getRow("bad_string", "racial-slur", "the_info") | ||
|
|
||
| setupMocks(getDbMock, [firstRow]) | ||
|
|
||
| data = {'content': ''} | ||
| text = Text(**data) | ||
| output = check_words(text) | ||
|
|
||
| expected = [] | ||
| assert output == expected, "Actual: " + str(output) + " Expected: " + str(expected) | ||
|
|
||
| @patch('main.getDb') | ||
| def test_single_flagged_string_in_content(self,getDbMock): | ||
| firstRow = getRow("bad_string", "racial-slur", "the_info") | ||
|
|
||
| setupMocks(getDbMock, [firstRow]) | ||
|
|
||
| data = {'content': 'bad_string'} | ||
| text = Text(**data) | ||
| output = check_words(text) | ||
|
|
||
| expected = [{"line":1, "word":"bad_string", "additional_info":"the_info"}] | ||
| assert output == expected, "Actual: " + str(output) + " Expected: " + str(expected) | ||
|
|
||
| @patch('main.getDb') | ||
| def test_single_flagged_string_and_valid_string_in_content(self,getDbMock): | ||
| firstRow = getRow("bad_string", "racial-slur", "the_info") | ||
|
|
||
| setupMocks(getDbMock, [firstRow]) | ||
|
|
||
| data = {'content': 'bad_string\nokay_string'} | ||
| text = Text(**data) | ||
| output = check_words(text) | ||
|
|
||
| expected = [{"line":1, "word":"bad_string", "additional_info":"the_info"}] | ||
| assert output == expected, "Actual: " + str(output) + " Expected: " + str(expected) | ||
|
|
||
| @patch('main.getDb') | ||
| def test_multiple_flagged_strings_existing_records(self,getDbMock): | ||
|
|
||
| firstRow = getRow("bad_string", "racial-slur", "the_info") | ||
| secondRow = getRow("bad_string_2", "racial-slur", "the_info_2") | ||
| thirdRow = getRow("biased_thing", "other", "the_info_3") | ||
|
|
||
| setupMocks(getDbMock, [firstRow, secondRow, thirdRow]) | ||
|
|
||
| data = {'content': 'bad_string\nbad_string_2'} | ||
| text = Text(**data) | ||
| output = check_words(text) | ||
|
|
||
| expected = [{"line":1, "word":"bad_string", "additional_info":"the_info"}, | ||
| {"line":2, "word":"bad_string", "additional_info":"the_info"}, | ||
| {"line":2, "word":"bad_string_2", "additional_info":"the_info_2"}] | ||
| assert output == expected, "Actual: " + str(output) + " Expected: " + str(expected) | ||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| from couchdb.client import Document | ||
| from couchdb.client import Row | ||
| from unittest.mock import MagicMock | ||
|
|
||
| def getRow(flaggedString, category, info): | ||
upkarlidder marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| firstDoc = Document() | ||
| firstDoc["flagged_string"] = flaggedString | ||
| firstDoc["category"] = category | ||
| firstDoc["info"] = info | ||
| firstRow = Row() | ||
| firstRow['doc'] = firstDoc | ||
| return firstRow | ||
|
|
||
| def setupMocks(getDbMock, rows): | ||
| mockDbViewResults = MagicMock() | ||
| mockDbViewResults.return_value = iter(rows) | ||
| dbMock = MagicMock() | ||
| dbMock.view = mockDbViewResults | ||
| getDbMock.return_value=dbMock | ||
Uh oh!
There was an error while loading. Please reload this page.