kb topic search + client-ip port strip + application notes html
This commit is contained in:
45
tests/test_core/test_clientip.py
Normal file
45
tests/test_core/test_clientip.py
Normal file
@@ -0,0 +1,45 @@
|
||||
"""strip_port / client_ip normalization (ARR forwards clientip:port)."""
|
||||
|
||||
from shopdb.utils.clientip import strip_port, client_ip
|
||||
|
||||
|
||||
def test_strip_ipv4_port():
|
||||
assert strip_port('10.134.48.20:52344') == '10.134.48.20'
|
||||
|
||||
|
||||
def test_ipv4_without_port_untouched():
|
||||
assert strip_port('10.134.48.20') == '10.134.48.20'
|
||||
|
||||
|
||||
def test_bare_ipv6_untouched():
|
||||
assert strip_port('2001:db8::1') == '2001:db8::1'
|
||||
|
||||
|
||||
def test_bracketed_ipv6_with_port():
|
||||
assert strip_port('[2001:db8::1]:443') == '2001:db8::1'
|
||||
|
||||
|
||||
def test_bracketed_ipv6_without_port():
|
||||
assert strip_port('[2001:db8::1]') == '2001:db8::1'
|
||||
|
||||
|
||||
def test_none_and_empty_safe():
|
||||
assert strip_port(None) is None
|
||||
assert strip_port('') == ''
|
||||
|
||||
|
||||
class _FakeRequest:
|
||||
def __init__(self, headers=None, remote_addr=None):
|
||||
self.headers = headers or {}
|
||||
self.remote_addr = remote_addr
|
||||
|
||||
|
||||
def test_client_ip_prefers_forwarded_first_hop_stripped():
|
||||
request_obj = _FakeRequest(headers={'X-Forwarded-For': '10.0.0.5:51000, 10.0.0.1'},
|
||||
remote_addr='127.0.0.1')
|
||||
assert client_ip(request_obj) == '10.0.0.5'
|
||||
|
||||
|
||||
def test_client_ip_falls_back_to_remote_addr_stripped():
|
||||
request_obj = _FakeRequest(headers={}, remote_addr='192.168.1.9:60000')
|
||||
assert client_ip(request_obj) == '192.168.1.9'
|
||||
@@ -32,3 +32,36 @@ def test_create_requires_shortdescription(client, db, auth_headers):
|
||||
json={'linkurl': 'https://kb.example/x'},
|
||||
headers=auth_headers)
|
||||
assert resp.status_code == 400
|
||||
|
||||
|
||||
def test_search_matches_topic_appname(client, db, auth_headers):
|
||||
"""Searching a topic (Application name) returns every article under it, not
|
||||
just the one whose title/keywords happen to contain the word.
|
||||
|
||||
Regression: KB list search omitted the topic, so a topic-only match (e.g.
|
||||
'Spotfire' as the app) surfaced a single article instead of all of them.
|
||||
"""
|
||||
from shopdb.core.models import Application
|
||||
|
||||
app_row = Application(appname='Spotfire')
|
||||
db.session.add(app_row)
|
||||
db.session.flush()
|
||||
|
||||
# Two articles whose title/keywords do NOT contain 'Spotfire' - only the
|
||||
# topic (appid) ties them to it - plus one that does mention it directly.
|
||||
for payload in [
|
||||
{'shortdescription': 'Dashboard login steps', 'keywords': 'login',
|
||||
'linkurl': 'https://kb.example/a', 'appid': app_row.appid},
|
||||
{'shortdescription': 'Export a visualization', 'keywords': 'export',
|
||||
'linkurl': 'https://kb.example/b', 'appid': app_row.appid},
|
||||
{'shortdescription': 'Spotfire install guide', 'keywords': 'install',
|
||||
'linkurl': 'https://kb.example/c', 'appid': app_row.appid},
|
||||
]:
|
||||
resp = client.post('/api/knowledgebase', json=payload, headers=auth_headers)
|
||||
assert resp.status_code == 201, resp.get_json()
|
||||
|
||||
listing = client.get('/api/knowledgebase?search=Spotfire', headers=auth_headers)
|
||||
assert listing.status_code == 200
|
||||
urls = {a['linkurl'] for a in listing.get_json()['data']}
|
||||
assert {'https://kb.example/a', 'https://kb.example/b',
|
||||
'https://kb.example/c'} <= urls
|
||||
|
||||
Reference in New Issue
Block a user