Extract employee directory into a plugin
Third core feature pulled into a plugin (blueprint-only, like slides). The employee directory is a read-only lookup over a separate HR database. - plugins/employees/: manifest (api_prefix /api/employees, no deps), api/ (moved blueprint, contract-pure: success/error/ErrorCodes + employee_connection all from shopdb.api), plugin.py (get_blueprint, get_models -> []). - employee_connection STAYS core infrastructure in shopdb.api (config-driven external DB connector, shared by search + the notifications shopfloor feed). So no get_services needed and no contract change - the plugin owns the directory FEATURE, core owns the shared connector. - Fixed a latent bug in the move: error paths used ErrorCodes.DATABASE_ERROR which does not exist -> ErrorCodes.INTERNAL_ERROR (so a directory outage now returns a clean 500 envelope instead of an AttributeError crash). - De-cored: deleted shopdb/core/api/employees.py, removed from CORE_BLUEPRINT_NAMES + core/api/__init__ import/__all__. Registered in instance/plugins.json. Pinned first: validation (400) + graceful-degrade (500) characterization tests; the degrade test caught the DATABASE_ERROR bug and goes green with the fix. 184 tests pass, naming green, app boots 9 bundled plugins, endpoint verified live. Plugin extractions complete: knowledgebase, slides, employees. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
26
tests/test_core/test_employees.py
Normal file
26
tests/test_core/test_employees.py
Normal file
@@ -0,0 +1,26 @@
|
||||
"""Characterization tests for the employee directory endpoints.
|
||||
|
||||
Written before extracting employees into a plugin. The wjf_employees DB is not
|
||||
available under test, so these assert the DB-independent behaviors: validation
|
||||
(400) and graceful failure (500 envelope, not an unhandled crash) when the
|
||||
directory is unreachable. Behavior must be identical as a plugin blueprint.
|
||||
"""
|
||||
|
||||
|
||||
def test_search_requires_min_query(client, db):
|
||||
"""A too-short query is rejected before touching the directory DB."""
|
||||
resp = client.get('/api/employees/search?q=a')
|
||||
assert resp.status_code == 400
|
||||
|
||||
|
||||
def test_lookup_requires_numeric_sso(client, db):
|
||||
"""Non-numeric SSO is rejected without touching the directory DB."""
|
||||
resp = client.get('/api/employees/lookup/abc')
|
||||
assert resp.status_code == 400
|
||||
|
||||
|
||||
def test_search_degrades_when_directory_unreachable(client, db):
|
||||
"""With the directory DB unavailable, search returns a clean 500 envelope."""
|
||||
resp = client.get('/api/employees/search?q=smith')
|
||||
assert resp.status_code == 500
|
||||
assert resp.get_json()['status'] == 'error'
|
||||
@@ -17,7 +17,7 @@ from shopdb.plugins import plugin_manager
|
||||
from shopdb.plugins.base import BasePlugin, PluginMeta
|
||||
|
||||
|
||||
BUNDLED_PLUGINS = ('computers', 'equipment', 'knowledgebase', 'network', 'notifications', 'printers', 'slides', 'usb')
|
||||
BUNDLED_PLUGINS = ('computers', 'employees', 'equipment', 'knowledgebase', 'network', 'notifications', 'printers', 'slides', 'usb')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -94,6 +94,7 @@ def test_plugin_loader_discovers_bundled_plugins(app):
|
||||
|
||||
expected_plugins = {
|
||||
'computers',
|
||||
'employees',
|
||||
'equipment',
|
||||
'knowledgebase',
|
||||
'network',
|
||||
|
||||
Reference in New Issue
Block a user