Skip to content

Commit 422dba8

Browse files
committed
adding fake data to the common_api
Addressing Issues 458 & 425 Adds deployment strategy: Recreate This is instead of the default Rollling deployment, which fails because the DB is RWO, so we have to kill old server container before starting new. Updates exec_status every 100 rows
1 parent 91c6e93 commit 422dba8

File tree

6 files changed

+163
-14
lines changed

6 files changed

+163
-14
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ start_env.sh
2222
/src/server/local_files/
2323
.mypy_cache/
2424
*secrets*
25-
*kustomization*
25+
*kustomization*

src/helm-chart/templates/deployment.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ spec:
88
{{- if not .Values.autoscaling.enabled }}
99
replicas: {{ .Values.replicaCount }}
1010
{{- end }}
11+
strategy:
12+
type: Recreate
1113
selector:
1214
matchLabels:
1315
{{- include "helm-chart.selectorLabels" . | nindent 6 }}

src/server/api/common_api.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,22 @@
66
import time
77
from datetime import datetime
88

9+
from api.fake_data import sl_mock_data
10+
911
try:
1012
from secrets_dict import SHELTERLUV_SECRET_TOKEN
1113
except ImportError:
1214
# Not running locally
1315
print("Couldn't get SHELTERLUV_SECRET_TOKEN from file, trying environment **********")
14-
from os import environ
15-
16-
try:
17-
SHELTERLUV_SECRET_TOKEN = environ['SHELTERLUV_SECRET_TOKEN']
18-
except KeyError:
19-
# Nor in environment
20-
# You're SOL for now
21-
print("Couldn't get secrets from file or environment")
22-
16+
from os import getenv
2317

18+
SHELTERLUV_SECRET_TOKEN = getenv('SHELTERLUV_SECRET_TOKEN')
19+
if not SHELTERLUV_SECRET_TOKEN:
20+
print("Couldn't get secrets from file or environment",
21+
"Defaulting to Fake Data")
2422

2523
from api import jwt_ops
2624

27-
2825
@common_api.route('/api/timeout_test/<duration>', methods=['GET'])
2926
def get_timeout(duration):
3027
start = datetime.now().strftime("%H:%M:%S");
@@ -178,7 +175,6 @@ def get_360(matching_id):
178175

179176
return jsonify({'result': result})
180177

181-
182178
@common_api.route('/api/person/<matching_id>/animals', methods=['GET'])
183179
@jwt_ops.jwt_required()
184180
def get_animals(matching_id):
@@ -187,6 +183,9 @@ def get_animals(matching_id):
187183
"animal_details": {}
188184
}
189185

186+
if not SHELTERLUV_SECRET_TOKEN:
187+
return jsonify(sl_mock_data('animals'))
188+
190189
with engine.connect() as connection:
191190
query = text("select * from pdp_contacts where matching_id = :matching_id and source_type = 'shelterluvpeople' and archived_date is null")
192191
query_result = connection.execute(query, matching_id=matching_id)
@@ -212,6 +211,10 @@ def get_animals(matching_id):
212211
def get_person_animal_events(matching_id, animal_id):
213212
result = {}
214213
events = []
214+
215+
if not SHELTERLUV_SECRET_TOKEN:
216+
return jsonify(sl_mock_data('events'))
217+
215218
with engine.connect() as connection:
216219
query = text("select * from pdp_contacts where matching_id = :matching_id and source_type = 'shelterluvpeople' and archived_date is null")
217220
query_result = connection.execute(query, matching_id=matching_id)

src/server/api/fake_data.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
""" Fake data that can be returned when an API token is missing for local
2+
development, or for running pytest
3+
4+
Shelterluv Data contains:
5+
Matched: Animal & Event End point
6+
"""
7+
8+
shelterluv_data = {
9+
'animals': {
10+
"animal_details": {
11+
'12345': {
12+
"Age": 24,
13+
"DOBUnixTime": 1568480456,
14+
"Name": "Lola aka Fake Cat",
15+
"Type": "Cat",
16+
"Photos":
17+
["https://images.unsplash.com/photo-1456926631375-92c8ce872def?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8OHx8YW5pbWFsfGVufDB8fDB8fA%3D%3D&w=1000&q=80"],
18+
"Status": "Healthy In Home",
19+
},
20+
},
21+
"person_details": {
22+
"shelterluv_short_id": 2,
23+
},
24+
},
25+
'events': {
26+
'12345':[
27+
{
28+
'AssociatedRecords': [
29+
{'Id': 12345, 'Type': 'Animal' },
30+
{'Id': 12345, 'Type': 'Person'},
31+
],
32+
'Subtype': 'Foster Home',
33+
'Time': '1602694822',
34+
'Type': 'Outcome.Adoption',
35+
'User': 'Fake User',
36+
},
37+
]
38+
},
39+
}
40+
41+
42+
def sl_mock_data(end_point: str)-> dict:
43+
""" Shelterluv mock data.
44+
Takes the end_point as a str of `animals` or `events` and returns
45+
a dict representing a test data for that end_point.
46+
"""
47+
48+
return shelterluv_data.get(end_point)

src/server/pipeline/match_data.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,15 @@ def start(connection, added_or_updated_rows, manual_matches_df, job_id):
5050

5151
rows = items_to_update.to_dict(orient="records")
5252
row_print_freq = 1000
53+
db_update_freq = 100 # update db after this many rows
5354

5455
for row_num, row in enumerate(rows):
55-
if row_num % row_print_freq == 0:
56+
if row_num % row_print_freq == 0: # Write to log
5657
current_app.logger.info("- Matching rows {}-{} of {}".format(
5758
row_num + 1, min(len(rows), row_num + row_print_freq), len(rows))
5859
)
60+
61+
if row_num % db_update_freq == 0: # Update execution_status table
5962
log_db.log_exec_status(job_id, 'matching', 'executing', str({'at_row': row_num + 1, 'of_rows': len(rows) }) )
6063

6164
# Exact matches based on specified columns

src/server/test_api.py

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@
3131
SERVER_URL = "http://server:5000"
3232
IS_LOCAL = False
3333

34+
try:
35+
from secrets_dict import SHELTERLUV_SECRET_TOKEN
36+
except ImportError:
37+
SHELTERLUV_SECRET_TOKEN = os.getenv("SHELTERLUV_SECRET_TOKEN")
38+
39+
SL_Token = True if SHELTERLUV_SECRET_TOKEN else False
40+
print(os.getenv("SHELTERLUV_SECRET_TOKEN"))
41+
42+
43+
3444
### DNS lookup tests ##############################
3545

3646
def test_bad_dns():
@@ -139,8 +149,90 @@ def test_inact_userblocked(state: State):
139149
assert response.status_code == 401
140150

141151

152+
### Shelterluv API tests ######################################
153+
154+
@pytest.mark.skipif(SL_Token, reason="Not run when SL_Token Present")
155+
def test_user_get_person_animal_events(state: State):
156+
""" Test that the api returns mock data if the Shelterluv Token
157+
is missing from secrets
158+
"""
159+
160+
# Build auth string value including token from state
161+
b_string = 'Bearer ' + state.state['base_user']
162+
163+
assert len(b_string) > 24
164+
165+
auth_hdr = {'Authorization' : b_string}
166+
url = SERVER_URL + "/api/person/12345/animal/12345/events"
167+
response = requests.get(url, headers = auth_hdr)
168+
169+
assert response.status_code == 200
170+
171+
from api.fake_data import sl_mock_data
172+
assert response.json() == sl_mock_data("events")
142173

143174

175+
@pytest.mark.skipif(SL_Token, reason="Not run when SL_Token Present")
176+
def test_user_get_animals(state: State):
177+
""" Test that the api returns mock data if the Shelterluv Token
178+
is missing from secrets
179+
"""
180+
181+
# Build auth string value including token from state
182+
b_string = 'Bearer ' + state.state['base_user']
183+
184+
assert len(b_string) > 24
185+
186+
auth_hdr = {'Authorization' : b_string}
187+
url = SERVER_URL + "/api/person/12345/animals"
188+
response = requests.get(url, headers = auth_hdr)
189+
190+
assert response.status_code == 200
191+
192+
from api.fake_data import sl_mock_data
193+
assert response.json() == sl_mock_data("animals")
194+
195+
196+
@pytest.mark.skipif(not SL_Token, reason="Run when SL_Token Present")
197+
def test_user_get_animals_sl_token(state: State):
198+
""" Test to confirm api does not return mock values if the Shelterluv Token
199+
is present in the secrets_dict file.
200+
Note this works on the assumption the SL token is not valid, and returns
201+
a default empty value
202+
"""
203+
204+
# Build auth string value including token from state
205+
b_string = 'Bearer ' + state.state['base_user']
206+
207+
assert len(b_string) > 24
208+
209+
auth_hdr = {'Authorization' : b_string}
210+
url = SERVER_URL + "/api/person/12345/animals"
211+
response = requests.get(url, headers = auth_hdr)
212+
213+
assert response.status_code == 200
214+
assert response.json() == {'person_details': {}, 'animal_details': {}}
215+
216+
217+
@pytest.mark.skipif(not SL_Token, reason="Run when SL_Token Present")
218+
def test_user_get_person_animal_events_sl_token(state: State):
219+
""" Test to confirm api does not return mock values if the Shelterluv Token
220+
is present in the secrets_dict file.
221+
Note this works on the assumption the SL token is not valid, and returns
222+
a default empty value
223+
"""
224+
225+
# Build auth string value including token from state
226+
b_string = 'Bearer ' + state.state['base_user']
227+
228+
assert len(b_string) > 24
229+
230+
auth_hdr = {'Authorization' : b_string}
231+
url = SERVER_URL + "/api/person/12345/animal/12345/events"
232+
response = requests.get(url, headers = auth_hdr)
233+
234+
assert response.status_code == 200
235+
assert response.json() == {}
144236

145237

146238
### Admin-level tests ######################################
@@ -261,4 +353,5 @@ def test_statistics(state: State):
261353
auth_hdr = {'Authorization' : b_string}
262354

263355
response = requests.get(SERVER_URL + "/api/statistics", headers=auth_hdr)
264-
assert response.status_code == 200
356+
assert response.status_code == 200
357+

0 commit comments

Comments
 (0)