Update processes API to use FeatureEntry entities (#2438)

This commit is contained in:
Daniel Smith 2022-11-06 13:00:26 -08:00 коммит произвёл GitHub
Родитель e2ce1d405e
Коммит 58e1dc4cf6
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 133 добавлений и 123 удалений

Просмотреть файл

@ -26,7 +26,7 @@ class ProcessesAPI(basehandlers.APIHandler):
"""Return the process of the feature."""
# Load feature directly from NDB so as to never get a stale cached copy.
feature_id = kwargs['feature_id']
f = core_models.Feature.get_by_id(feature_id)
f = core_models.FeatureEntry.get_by_id(feature_id)
if f is None:
self.abort(404, msg=f'Feature {feature_id} not found')
@ -44,13 +44,13 @@ class ProgressAPI(basehandlers.APIHandler):
def do_get(self, **kwargs):
"""Return the progress of the feature."""
feature_id = kwargs['feature_id']
f = core_models.Feature.get_by_id(feature_id)
if f is None:
fe = core_models.FeatureEntry.get_by_id(feature_id)
if fe is None:
self.abort(404, msg=f'Feature {feature_id} not found')
stages = core_models.Stage.get_feature_stages(fe.key.integer_id())
progress_so_far = {}
for progress_item, detector in list(processes.PROGRESS_DETECTORS.items()):
detected = detector(f)
detected = detector(fe, stages)
if detected:
progress_so_far[progress_item] = str(detected)
return progress_so_far

Просмотреть файл

@ -18,6 +18,7 @@ import testing_config # Must be imported before the module under test.
import flask
from api import processes_api
from internals import core_enums
from internals import core_models
from internals import processes
from internals import core_enums
@ -28,15 +29,22 @@ test_app = flask.Flask(__name__)
class ProcessesAPITest(testing_config.CustomTestCase):
def setUp(self):
self.feature_1 = core_models.Feature(
name='feature one', summary='sum', category=1)
self.feature_1 = core_models.FeatureEntry(
name='feature one', summary='sum', category=1, feature_type=0)
self.feature_1.put()
self.feature_id = self.feature_1.key.integer_id()
stage_types = [110, 120, 130, 140, 150, 151, 160]
self.stages: list[core_models.Stage] = []
for s_type in stage_types:
stage = core_models.Stage(feature_id=self.feature_id, stage_type=s_type)
stage.put()
self.stages.append(stage)
self.handler = processes_api.ProcessesAPI()
self.request_path = f'/api/v0/features/{self.feature_id}/process'
def tearDown(self):
for stage in self.stages:
stage.key.delete()
self.feature_1.key.delete()
def test_get__default_feature_type(self):
@ -82,17 +90,33 @@ class ProcessesAPITest(testing_config.CustomTestCase):
class ProgressAPITest(testing_config.CustomTestCase):
def setUp(self):
self.feature_1 = core_models.Feature(
self.feature_1 = core_models.FeatureEntry(
name='feature one', summary='sum Z',
owner=['feature_owner@example.com'],
ready_for_trial_url='fake ready for trial url',
intent_to_experiment_url='fake intent to experiment url',
owner_emails=['feature_owner@example.com'],
spec_link='fake spec link', category=1, web_dev_views=1,
impl_status_chrome=5, intent_stage=core_enums.INTENT_IMPLEMENT,
shipped_milestone=1)
feature_type=0)
self.feature_1.put()
self.feature_id = self.feature_1.key.integer_id()
stage_types = [110, 120, 130, 140, 150, 151, 160]
self.stages: list[core_models.Stage] = []
for s_type in stage_types:
stage = core_models.Stage(feature_id=self.feature_id, stage_type=s_type)
if s_type == 120:
stage.intent_thread_url = 'https://example.com/prototype'
elif s_type == 130:
stage.announcement_url = 'https://example.com/ready_for_trial'
elif s_type == 150:
stage.intent_thread_url = 'https://example.com/ot'
elif s_type == 151:
stage.intent_thread_url = 'https://example.com/extend'
elif s_type == 160:
stage.milestones = core_models.MilestoneSet(desktop_first=1)
stage.intent_thread_url = 'https://example.com/ship'
stage.put()
self.stages.append(stage)
self.handler = processes_api.ProgressAPI()
self.request_path = f'/api/v0/features/{self.feature_id}/progress'
@ -110,8 +134,10 @@ class ProgressAPITest(testing_config.CustomTestCase):
'Draft API spec': 'fake spec link',
'Estimated target milestone': 'True',
'Final target milestone': 'True',
'Intent to Experiment email': 'fake intent to experiment url',
'Ready for Trial email': 'fake ready for trial url',
'Intent to Prototype email': 'https://example.com/prototype',
'Intent to Experiment email': 'https://example.com/ot',
'Ready for Trial email': 'https://example.com/ready_for_trial',
'Intent to Ship email': 'https://example.com/ship',
'Spec link': 'fake spec link',
'Web developer signals': 'True',
}, actual)

Просмотреть файл

@ -17,7 +17,6 @@ import collections
from internals import approval_defs
from internals import core_enums
from internals import core_models
Process = collections.namedtuple(
@ -523,99 +522,94 @@ def review_is_done(status):
# be used as a link URL.
PROGRESS_DETECTORS = {
'Initial public proposal':
lambda f: f.initial_public_proposal_url,
lambda f, _: f.initial_public_proposal_url,
'Explainer':
lambda f: f.explainer_links and f.explainer_links[0],
lambda f, _: f.explainer_links and f.explainer_links[0],
'Security review issues addressed':
lambda f: review_is_done(f.security_review_status),
lambda f, _: review_is_done(f.security_review_status),
'Privacy review issues addressed':
lambda f: review_is_done(f.privacy_review_status),
lambda f, _: review_is_done(f.privacy_review_status),
'Intent to Prototype email':
lambda f: f.intent_to_implement_url,
lambda f, stages: (
core_enums.STAGE_TYPES_PROTOTYPE[f.feature_type] and
stages[core_enums.STAGE_TYPES_PROTOTYPE[f.feature_type]].intent_thread_url),
'Intent to Ship email':
lambda f: f.intent_to_ship_url,
lambda f, stages: (core_enums.STAGE_TYPES_SHIPPING[f.feature_type] and
stages[core_enums.STAGE_TYPES_SHIPPING[f.feature_type]].intent_thread_url),
'Ready for Trial email':
lambda f: f.ready_for_trial_url,
lambda f, stages: (core_enums.STAGE_TYPES_DEV_TRIAL[f.feature_type] and
stages[core_enums.STAGE_TYPES_DEV_TRIAL[f.feature_type]].announcement_url),
'Intent to Experiment email':
lambda f: f.intent_to_experiment_url,
'One LGTM on Intent to Experiment':
lambda f: f.i2e_lgtms,
'One LGTM on Request for Deprecation Trial':
lambda f: f.i2e_lgtms,
'Three LGTMs on Intent to Ship':
lambda f: f.i2s_lgtms and len(f.i2s_lgtms) >= 3,
lambda f, stages: (core_enums.STAGE_TYPES_ORIGIN_TRIAL[f.feature_type] and
stages[core_enums.STAGE_TYPES_ORIGIN_TRIAL[f.feature_type]].intent_thread_url),
'Samples':
lambda f: f.sample_links and f.sample_links[0],
lambda f, _: f.sample_links and f.sample_links[0],
'Doc links':
lambda f: f.doc_links and f.doc_links[0],
lambda f, _: f.doc_links and f.doc_links[0],
'Spec link':
lambda f: f.spec_link,
lambda f, _: f.spec_link,
'Draft API spec':
lambda f: f.spec_link,
lambda f, _: f.spec_link,
'API spec':
lambda f: f.api_spec,
lambda f, _: f.api_spec,
'Spec mentor':
lambda f: f.spec_mentors,
lambda f, _: f.spec_mentor_emails,
'TAG review requested':
lambda f: f.tag_review,
lambda f, _: f.tag_review,
'TAG review issues addressed':
lambda f: review_is_done(f.tag_review_status),
lambda f, _: review_is_done(f.tag_review_status),
'Web developer signals':
lambda f: bool(f.web_dev_views and
f.web_dev_views != core_enums.DEV_NO_SIGNALS),
lambda f, _: bool(f.web_dev_views and
f.web_dev_views != core_enums.DEV_NO_SIGNALS),
'Vendor signals':
lambda f: bool(
lambda f, _: bool(
f.ff_views != core_enums.NO_PUBLIC_SIGNALS or
f.safari_views != core_enums.NO_PUBLIC_SIGNALS or
f.ie_views != core_enums.NO_PUBLIC_SIGNALS), # IE Deprecated
f.safari_views != core_enums.NO_PUBLIC_SIGNALS),
'Updated vendor signals':
lambda f: bool(
lambda f, _: bool(
f.ff_views != core_enums.NO_PUBLIC_SIGNALS or
f.safari_views != core_enums.NO_PUBLIC_SIGNALS or
f.ie_views != core_enums.NO_PUBLIC_SIGNALS), # IE Deprecated
f.safari_views != core_enums.NO_PUBLIC_SIGNALS),
'Final vendor signals':
lambda f: bool(
lambda f, _: bool(
f.ff_views != core_enums.NO_PUBLIC_SIGNALS or
f.safari_views != core_enums.NO_PUBLIC_SIGNALS or
f.ie_views != core_enums.NO_PUBLIC_SIGNALS), # IE Deprecated
f.safari_views != core_enums.NO_PUBLIC_SIGNALS),
'Estimated target milestone':
lambda f: bool(f.shipped_milestone),
lambda f, stages: bool(core_enums.STAGE_TYPES_SHIPPING[f.feature_type] and
stages[core_enums.STAGE_TYPES_SHIPPING[f.feature_type]].milestones.desktop_first),
'Final target milestone':
lambda f: bool(f.shipped_milestone),
lambda f, stages: bool(core_enums.STAGE_TYPES_SHIPPING[f.feature_type] and
stages[core_enums.STAGE_TYPES_SHIPPING[f.feature_type]].milestones.desktop_first),
'Code in Chromium':
lambda f: f.impl_status_chrome in (
lambda f, _: f.impl_status_chrome in (
core_enums.IN_DEVELOPMENT, core_enums.BEHIND_A_FLAG,
core_enums.ENABLED_BY_DEFAULT,
core_enums.ORIGIN_TRIAL, core_enums.INTERVENTION),
'Motivation':
lambda f: bool(f.motivation),
lambda f, _: bool(f.motivation),
'Code removed':
lambda f: f.impl_status_chrome == core_enums.REMOVED,
lambda f, _: f.impl_status_chrome == core_enums.REMOVED,
}

Просмотреть файл

@ -141,140 +141,130 @@ class ProcessesWellFormedTest(testing_config.CustomTestCase):
class ProgressDetectorsTest(testing_config.CustomTestCase):
def setUp(self):
self.feature_1 = core_models.Feature(
self.feature_1 = core_models.FeatureEntry(
name='feature one', summary='sum', category=1,
intent_stage=core_enums.INTENT_IMPLEMENT)
intent_stage=core_enums.INTENT_IMPLEMENT, feature_type=0)
self.feature_1.put()
stage_types = [110, 120, 130, 140, 150, 151, 160]
self.stages: list[core_models.Stage] = []
for s_type in stage_types:
stage = core_models.Stage(feature_id=self.feature_1.key.integer_id(),
stage_type=s_type)
stage.put()
self.stages.append(stage)
self.stages_dict = core_models.Stage.get_feature_stages(
self.feature_1.key.integer_id())
def tearDown(self):
self.feature_1.key.delete()
for stage in self.stages:
stage.key.delete()
def test_initial_public_proposal_url(self):
detector = processes.PROGRESS_DETECTORS['Initial public proposal']
self.assertFalse(detector(self.feature_1))
self.assertFalse(detector(self.feature_1, self.stages_dict))
self.feature_1.initial_public_proposal_url = 'http://example.com'
self.assertTrue(detector(self.feature_1))
self.assertTrue(detector(self.feature_1, self.stages_dict))
def test_explainer(self):
detector = processes.PROGRESS_DETECTORS['Explainer']
self.assertFalse(detector(self.feature_1))
self.assertFalse(detector(self.feature_1, self.stages_dict))
self.feature_1.explainer_links = ['http://example.com']
self.assertTrue(detector(self.feature_1))
self.assertTrue(detector(self.feature_1, self.stages_dict))
def test_security_review_completed(self):
detector = processes.PROGRESS_DETECTORS['Security review issues addressed']
self.assertFalse(detector(self.feature_1))
self.assertFalse(detector(self.feature_1, self.stages_dict))
self.feature_1.security_review_status = core_enums.REVIEW_ISSUES_ADDRESSED
self.assertTrue(detector(self.feature_1))
self.assertTrue(detector(self.feature_1, self.stages_dict))
def test_privacy_review_completed(self):
detector = processes.PROGRESS_DETECTORS['Privacy review issues addressed']
self.assertFalse(detector(self.feature_1))
self.assertFalse(detector(self.feature_1, self.stages_dict))
self.feature_1.privacy_review_status = core_enums.REVIEW_ISSUES_ADDRESSED
self.assertTrue(detector(self.feature_1))
self.assertTrue(detector(self.feature_1, self.stages_dict))
def test_intent_to_prototype_email(self):
detector = processes.PROGRESS_DETECTORS['Intent to Prototype email']
self.assertFalse(detector(self.feature_1))
self.feature_1.intent_to_implement_url = 'http://example.com'
self.assertTrue(detector(self.feature_1))
self.assertFalse(detector(self.feature_1, self.stages_dict))
self.stages_dict[120].intent_thread_url = 'http://example.com/prototype'
self.assertTrue(detector(self.feature_1, self.stages_dict))
def test_intent_to_ship_email(self):
detector = processes.PROGRESS_DETECTORS['Intent to Ship email']
self.assertFalse(detector(self.feature_1))
self.feature_1.intent_to_ship_url = 'http://example.com'
self.assertTrue(detector(self.feature_1))
self.assertFalse(detector(self.feature_1, self.stages_dict))
self.stages_dict[160].intent_thread_url = 'http://example.com/ship'
self.assertTrue(detector(self.feature_1, self.stages_dict))
def test_ready_for_trial_email(self):
detector = processes.PROGRESS_DETECTORS['Ready for Trial email']
self.assertFalse(detector(self.feature_1))
self.feature_1.ready_for_trial_url = 'http://example.com'
self.assertTrue(detector(self.feature_1))
self.assertFalse(detector(self.feature_1, self.stages_dict))
self.stages_dict[130].announcement_url = 'http://example.com/trial_ready'
self.assertTrue(detector(self.feature_1, self.stages_dict))
def test_intent_to_experiment_email(self):
detector = processes.PROGRESS_DETECTORS['Intent to Experiment email']
self.assertFalse(detector(self.feature_1))
self.feature_1.intent_to_experiment_url = 'http://example.com'
self.assertTrue(detector(self.feature_1))
def test_one_i2e_lgtm(self):
detector = processes.PROGRESS_DETECTORS['One LGTM on Intent to Experiment']
self.assertFalse(detector(self.feature_1))
self.feature_1.i2e_lgtms = ['api_owner@chromium.org']
self.assertTrue(detector(self.feature_1))
def test_two_i2e_lgtm(self):
detector = processes.PROGRESS_DETECTORS[
'One LGTM on Request for Deprecation Trial']
self.assertFalse(detector(self.feature_1))
self.feature_1.i2e_lgtms = ['api_owner@chromium.org']
self.assertTrue(detector(self.feature_1))
def test_three_i2s_lgtm(self):
detector = processes.PROGRESS_DETECTORS['Three LGTMs on Intent to Ship']
self.assertFalse(detector(self.feature_1))
self.feature_1.i2s_lgtms = [
'one@chromium.org',
'two@chromium.org',
'three@chromium.org']
self.assertTrue(detector(self.feature_1))
self.assertFalse(detector(self.feature_1, self.stages_dict))
self.stages_dict[150].intent_thread_url = 'http://example.com/ot'
self.assertTrue(detector(self.feature_1, self.stages_dict))
def test_samples(self):
detector = processes.PROGRESS_DETECTORS['Samples']
self.assertFalse(detector(self.feature_1))
self.assertFalse(detector(self.feature_1, self.stages_dict))
self.feature_1.sample_links = ['http://example.com']
self.assertTrue(detector(self.feature_1))
self.assertTrue(detector(self.feature_1, self.stages_dict))
def test_doc_links(self):
detector = processes.PROGRESS_DETECTORS['Doc links']
self.assertFalse(detector(self.feature_1))
self.assertFalse(detector(self.feature_1, self.stages_dict))
self.feature_1.doc_links = ['http://example.com']
self.assertTrue(detector(self.feature_1))
self.assertTrue(detector(self.feature_1, self.stages_dict))
def test_tag_review_requested(self):
detector = processes.PROGRESS_DETECTORS['TAG review requested']
self.assertFalse(detector(self.feature_1))
self.assertFalse(detector(self.feature_1, self.stages_dict))
self.feature_1.tag_review = 'http://example.com'
self.assertTrue(detector(self.feature_1))
self.assertTrue(detector(self.feature_1, self.stages_dict))
def test_tag_review_completed(self):
detector = processes.PROGRESS_DETECTORS['TAG review issues addressed']
self.assertFalse(detector(self.feature_1))
self.assertFalse(detector(self.feature_1, self.stages_dict))
self.feature_1.tag_review_status = core_enums.REVIEW_ISSUES_ADDRESSED
self.assertTrue(detector(self.feature_1))
self.assertTrue(detector(self.feature_1, self.stages_dict))
def test_web_dav_signals(self):
def test_web_dev_signals(self):
detector = processes.PROGRESS_DETECTORS['Web developer signals']
self.assertFalse(detector(self.feature_1))
self.assertFalse(detector(self.feature_1, self.stages_dict))
self.feature_1.web_dev_views = core_enums.PUBLIC_SUPPORT
self.assertTrue(detector(self.feature_1))
self.assertTrue(detector(self.feature_1, self.stages_dict))
def test_vendor_signals(self):
detector = processes.PROGRESS_DETECTORS['Vendor signals']
self.assertFalse(detector(self.feature_1))
self.assertFalse(detector(self.feature_1, self.stages_dict))
self.feature_1.ff_views = core_enums.PUBLIC_SUPPORT
self.assertTrue(detector(self.feature_1))
self.assertTrue(detector(self.feature_1, self.stages_dict))
def test_estimated_target_milestone(self):
detector = processes.PROGRESS_DETECTORS['Estimated target milestone']
self.assertFalse(detector(self.feature_1))
self.feature_1.shipped_milestone = 99
self.assertTrue(detector(self.feature_1))
self.stages_dict[160].milestones = core_models.MilestoneSet()
self.assertFalse(detector(self.feature_1, self.stages_dict))
self.stages_dict[160].milestones.desktop_first = 99
self.assertTrue(detector(self.feature_1, self.stages_dict))
def test_code_in_chromium(self):
detector = processes.PROGRESS_DETECTORS['Code in Chromium']
self.assertFalse(detector(self.feature_1))
self.assertFalse(detector(self.feature_1, self.stages_dict))
self.feature_1.impl_status_chrome = core_enums.ENABLED_BY_DEFAULT
self.assertTrue(detector(self.feature_1))
self.assertTrue(detector(self.feature_1, self.stages_dict))
def test_motivation(self):
detector = processes.PROGRESS_DETECTORS['Motivation']
self.assertFalse(detector(self.feature_1))
self.assertFalse(detector(self.feature_1, self.stages_dict))
self.feature_1.motivation = 'test motivation'
self.assertTrue(detector(self.feature_1))
self.assertTrue(detector(self.feature_1, self.stages_dict))
def test_code_removed(self):
detector = processes.PROGRESS_DETECTORS['Code removed']
self.assertFalse(detector(self.feature_1))
self.assertFalse(detector(self.feature_1, self.stages_dict))
self.feature_1.impl_status_chrome = core_enums.REMOVED
self.assertTrue(detector(self.feature_1))
self.assertTrue(detector(self.feature_1, self.stages_dict))