Added unit tests and logging
This commit is contained in:
Родитель
dcf844ee28
Коммит
943c22be9e
|
@ -19,6 +19,7 @@ from datetime import datetime
|
|||
import flask
|
||||
from unittest import mock
|
||||
import werkzeug.exceptions # Flask HTTP stuff.
|
||||
from google.cloud import ndb # type: ignore
|
||||
|
||||
from api import feature_latency_api
|
||||
from internals.core_enums import *
|
||||
|
@ -45,11 +46,11 @@ class FeatureLatencyAPITest(testing_config.CustomTestCase):
|
|||
|
||||
def setUp(self):
|
||||
self.handler = feature_latency_api.FeatureLatencyAPI()
|
||||
self.request_path = '/api/v0/feature_latency'
|
||||
self.request_path = '/api/v0/feature-latency'
|
||||
|
||||
self.fe_1, self.fe_1_id = make_feature(
|
||||
self.fe_1a, self.fe_1a_id = make_feature(
|
||||
'has no milestone', (2023, 2, 18), ENABLED_BY_DEFAULT, None)
|
||||
self.fe_1, self.fe_1_id = make_feature(
|
||||
self.fe_1b, self.fe_1b_id = make_feature(
|
||||
'not a launch status', (2023, 2, 18), NO_ACTIVE_DEV, 119)
|
||||
self.fe_2, self.fe_2_id = make_feature(
|
||||
'launched before start', (2022, 8, 19), ENABLED_BY_DEFAULT, 108)
|
||||
|
|
|
@ -45,9 +45,13 @@ class ReviewLatencyAPI(basehandlers.APIHandler):
|
|||
Returns:
|
||||
A list of data on all public origin trials.
|
||||
"""
|
||||
gates = self.get_recently_reviewed_gates(DEFAULT_RECENT_DAYS)
|
||||
logging.info('gates %r', gates)
|
||||
today = kwargs.get('today')
|
||||
gates = self.get_recently_reviewed_gates(DEFAULT_RECENT_DAYS, today=today)
|
||||
gates_by_fid = self.organize_gates_by_feature_id(gates)
|
||||
for fid, feature_gates in gates_by_fid.items():
|
||||
logging.info('feautre %r:', fid)
|
||||
for fg in feature_gates:
|
||||
logging.info(' %r', fg)
|
||||
features = self.get_features_by_id(gates_by_fid.keys())
|
||||
features = self.sort_features_by_request(features, gates_by_fid)
|
||||
latencies_by_fid = {
|
||||
|
@ -57,9 +61,12 @@ class ReviewLatencyAPI(basehandlers.APIHandler):
|
|||
latencies_by_fid, features)
|
||||
return result
|
||||
|
||||
def get_recently_reviewed_gates(self, days) -> list[Gate]:
|
||||
def get_recently_reviewed_gates(
|
||||
self, days:int, today:datetime|None = None
|
||||
) -> list[Gate]:
|
||||
"""Retrieve a list of Gates responded to in recent days."""
|
||||
start_date = datetime.today() - timedelta(days=90)
|
||||
today = today or datetime.today()
|
||||
start_date = today - timedelta(days=90)
|
||||
gates_in_range = Gate.query(
|
||||
Gate.requested_on >= start_date).fetch()
|
||||
feature_ids = {g.feature_id for g in gates_in_range}
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
# Copyright 2024 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import testing_config # isort: split
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from unittest import mock
|
||||
from google.cloud import ndb # type: ignore
|
||||
|
||||
from api import review_latency_api
|
||||
from internals.core_enums import *
|
||||
from internals.core_models import FeatureEntry
|
||||
from internals.review_models import Gate
|
||||
|
||||
|
||||
def make_feature_and_gates(name):
|
||||
fe = FeatureEntry(name=name, summary='sum', category=1)
|
||||
fe.put()
|
||||
fe_id = fe.key.integer_id()
|
||||
g_1 = Gate(feature_id=fe_id, gate_type=1, stage_id=1, state=Gate.PREPARING)
|
||||
g_1.put()
|
||||
g_2 = Gate(feature_id=fe_id, gate_type=2, stage_id=1, state=Gate.PREPARING)
|
||||
g_2.put()
|
||||
g_3 = Gate(feature_id=fe_id, gate_type=3, stage_id=1, state=Gate.PREPARING)
|
||||
g_3.put()
|
||||
return fe, fe_id, g_1, g_2, g_3
|
||||
|
||||
|
||||
class ReviewLatencyAPITest(testing_config.CustomTestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.handler = review_latency_api.ReviewLatencyAPI()
|
||||
self.request_path = '/api/v0/review-latency'
|
||||
|
||||
self.fe_1, self.fe_1_id, self.g_1_1, self.g_1_2, self.g_1_3 = (
|
||||
make_feature_and_gates('Feature one'))
|
||||
self.fe_2, self.fe_2_id, self.g_2_1, self.g_2_2, self.g_2_3 = (
|
||||
make_feature_and_gates('Feature two'))
|
||||
self.today = datetime(2024, 3, 22)
|
||||
self.yesterday = datetime(2024, 3, 21)
|
||||
self.last_week = datetime(2024, 3, 15)
|
||||
|
||||
def tearDown(self):
|
||||
kinds: list[ndb.Model] = [FeatureEntry, Gate]
|
||||
for kind in kinds:
|
||||
for entity in kind.query():
|
||||
entity.key.delete()
|
||||
|
||||
def test_do_get__nothing_requested(self):
|
||||
"""When no reviews have been started, the result is empty."""
|
||||
actual = self.handler.do_get()
|
||||
self.assertEqual([], actual)
|
||||
|
||||
def test_do_get__normal(self):
|
||||
"""It produces a report of review latency."""
|
||||
self.g_1_1.requested_on = self.last_week
|
||||
self.g_1_1.responded_on = self.today
|
||||
self.g_1_1.put()
|
||||
self.g_1_2.requested_on = self.last_week
|
||||
self.g_1_2.put()
|
||||
|
||||
actual = self.handler.do_get()
|
||||
|
||||
expected = [
|
||||
{ 'feature': {'name': 'Feature one', 'id': self.fe_1_id},
|
||||
'gate_reviews': [
|
||||
{'gate_type': 1,
|
||||
'latency_days': 5},
|
||||
{'gate_type': 2,
|
||||
'latency_days': review_latency_api.PENDING_LATENCY},
|
||||
{'gate_type': 3,
|
||||
'latency_days': review_latency_api.NOT_STARTED_LATENCY},
|
||||
],
|
||||
}]
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_do_get__sorting(self):
|
||||
"""Multiple results are sorted by earlest review request."""
|
||||
self.g_1_1.requested_on = self.yesterday
|
||||
self.g_1_1.responded_on = self.today
|
||||
self.g_1_1.put()
|
||||
self.g_1_2.requested_on = self.today
|
||||
self.g_1_2.responded_on = self.today
|
||||
self.g_1_2.put()
|
||||
|
||||
self.g_2_1.requested_on = self.last_week
|
||||
self.g_2_1.responded_on = self.yesterday
|
||||
self.g_2_1.put()
|
||||
|
||||
actual = self.handler.do_get()
|
||||
|
||||
expected = [
|
||||
{ 'feature': {'name': 'Feature two', 'id': self.fe_2_id},
|
||||
'gate_reviews': [
|
||||
{'gate_type': 1,
|
||||
'latency_days': 4},
|
||||
{'gate_type': 2,
|
||||
'latency_days': review_latency_api.NOT_STARTED_LATENCY},
|
||||
{'gate_type': 3,
|
||||
'latency_days': review_latency_api.NOT_STARTED_LATENCY},
|
||||
],
|
||||
},
|
||||
{ 'feature': {'name': 'Feature one', 'id': self.fe_1_id},
|
||||
'gate_reviews': [
|
||||
{'gate_type': 1,
|
||||
'latency_days': 1},
|
||||
{'gate_type': 2,
|
||||
'latency_days': 0},
|
||||
{'gate_type': 3,
|
||||
'latency_days': review_latency_api.NOT_STARTED_LATENCY},
|
||||
],
|
||||
},
|
||||
]
|
||||
self.assertEqual(expected, actual)
|
Загрузка…
Ссылка в новой задаче