Skip to content

Commit 28007a4

Browse files
Added test_recommendation_service.py
1 parent 36a3240 commit 28007a4

2,040 files changed

Lines changed: 452699 additions & 36 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/recommendation/test_recommendation_service.py

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,57 @@
1-
import sys
2-
import os
31
import unittest
4-
from unittest.mock import MagicMock
5-
from demo_pb2 import ListRecommendationsRequest
6-
7-
# Ensure import works when run as script
8-
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
9-
2+
from unittest.mock import MagicMock, patch
103
from recommendation_server import RecommendationService
4+
from demo_pb2 import ListRecommendationsRequest, ListRecommendationsResponse
115

126

13-
class TestRecommendationService(unittest.TestCase):
14-
def test_list_recommendations(self):
15-
# Import the module after fixing path
16-
import recommendation_server
7+
class RecommendationServiceTest(unittest.TestCase):
178

18-
# Mock the global dependencies
9+
def setUp(self):
10+
# Inject logger and rec_svc_metrics manually since they aren't globally exposed
11+
import recommendation_server
1912
recommendation_server.logger = MagicMock()
20-
recommendation_server.tracer = MagicMock()
21-
recommendation_server.product_catalog_stub = MagicMock()
2213
recommendation_server.rec_svc_metrics = {
2314
"app_recommendations_counter": MagicMock()
2415
}
2516

26-
# Mock tracer context
27-
mock_span = MagicMock()
28-
recommendation_server.tracer.start_as_current_span.return_value.__enter__.return_value = mock_span
29-
30-
# Provide fake product data
31-
fake_products = [
32-
MagicMock(id="prod1"),
33-
MagicMock(id="prod2"),
34-
MagicMock(id="prod3"),
35-
MagicMock(id="prod4"),
36-
MagicMock(id="prod5"),
37-
MagicMock(id="prod6"),
38-
]
39-
recommendation_server.product_catalog_stub.ListProducts.return_value.products = fake_products
40-
41-
# Setup request
17+
@patch("recommendation_server.get_product_list")
18+
def test_excludes_input_products_and_limits_count(self, mock_get_products):
19+
mock_get_products.return_value = ["prod3", "prod4", "prod5"]
20+
4221
service = RecommendationService()
4322
request = ListRecommendationsRequest(product_ids=["prod1", "prod2"])
23+
context = MagicMock()
4424

45-
# Act
46-
response = service.ListRecommendations(request, MagicMock())
25+
response: ListRecommendationsResponse = service.ListRecommendations(request, context)
4726

48-
# Assert
49-
self.assertTrue(len(response.product_ids) > 0)
27+
self.assertIsInstance(response, ListRecommendationsResponse)
28+
self.assertEqual(response.product_ids, ["prod3", "prod4", "prod5"])
5029
self.assertNotIn("prod1", response.product_ids)
5130
self.assertNotIn("prod2", response.product_ids)
52-
self.assertLessEqual(len(response.product_ids), 5)
31+
32+
@patch("recommendation_server.get_product_list")
33+
def test_handles_empty_input(self, mock_get_products):
34+
mock_get_products.return_value = ["prod1", "prod2"]
35+
36+
service = RecommendationService()
37+
request = ListRecommendationsRequest(product_ids=[])
38+
context = MagicMock()
39+
40+
response = service.ListRecommendations(request, context)
41+
42+
self.assertEqual(response.product_ids, ["prod1", "prod2"])
43+
44+
@patch("recommendation_server.get_product_list")
45+
def test_handles_empty_catalog(self, mock_get_products):
46+
mock_get_products.return_value = []
47+
48+
service = RecommendationService()
49+
request = ListRecommendationsRequest(product_ids=["prod1"])
50+
context = MagicMock()
51+
52+
response = service.ListRecommendations(request, context)
53+
54+
self.assertEqual(response.product_ids, [])
5355

5456

5557
if __name__ == '__main__':
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pip
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2017 Laurent LAPORTE
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
Metadata-Version: 2.2
2+
Name: Deprecated
3+
Version: 1.2.18
4+
Summary: Python @deprecated decorator to deprecate old python classes, functions or methods.
5+
Home-page: https://github.com/laurent-laporte-pro/deprecated
6+
Author: Laurent LAPORTE
7+
Author-email: laurent.laporte.pro@gmail.com
8+
License: MIT
9+
Project-URL: Documentation, https://deprecated.readthedocs.io/en/latest/
10+
Project-URL: Source, https://github.com/laurent-laporte-pro/deprecated
11+
Project-URL: Bug Tracker, https://github.com/laurent-laporte-pro/deprecated/issues
12+
Keywords: deprecate,deprecated,deprecation,warning,warn,decorator
13+
Platform: any
14+
Classifier: Development Status :: 5 - Production/Stable
15+
Classifier: Environment :: Web Environment
16+
Classifier: Intended Audience :: Developers
17+
Classifier: License :: OSI Approved :: MIT License
18+
Classifier: Operating System :: OS Independent
19+
Classifier: Programming Language :: Python
20+
Classifier: Programming Language :: Python :: 2
21+
Classifier: Programming Language :: Python :: 2.7
22+
Classifier: Programming Language :: Python :: 3
23+
Classifier: Programming Language :: Python :: 3.4
24+
Classifier: Programming Language :: Python :: 3.5
25+
Classifier: Programming Language :: Python :: 3.6
26+
Classifier: Programming Language :: Python :: 3.7
27+
Classifier: Programming Language :: Python :: 3.8
28+
Classifier: Programming Language :: Python :: 3.9
29+
Classifier: Programming Language :: Python :: 3.10
30+
Classifier: Programming Language :: Python :: 3.11
31+
Classifier: Programming Language :: Python :: 3.12
32+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
33+
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
34+
Description-Content-Type: text/x-rst
35+
License-File: LICENSE.rst
36+
Requires-Dist: wrapt<2,>=1.10
37+
Provides-Extra: dev
38+
Requires-Dist: tox; extra == "dev"
39+
Requires-Dist: PyTest; extra == "dev"
40+
Requires-Dist: PyTest-Cov; extra == "dev"
41+
Requires-Dist: bump2version<1; extra == "dev"
42+
Requires-Dist: setuptools; python_version >= "3.12" and extra == "dev"
43+
Dynamic: author
44+
Dynamic: author-email
45+
Dynamic: classifier
46+
Dynamic: description
47+
Dynamic: description-content-type
48+
Dynamic: home-page
49+
Dynamic: keywords
50+
Dynamic: license
51+
Dynamic: platform
52+
Dynamic: project-url
53+
Dynamic: provides-extra
54+
Dynamic: requires-dist
55+
Dynamic: requires-python
56+
Dynamic: summary
57+
58+
59+
Deprecated Library
60+
------------------
61+
62+
Deprecated is Easy to Use
63+
`````````````````````````
64+
65+
If you need to mark a function or a method as deprecated,
66+
you can use the ``@deprecated`` decorator:
67+
68+
Save in a hello.py:
69+
70+
.. code:: python
71+
72+
from deprecated import deprecated
73+
74+
75+
@deprecated(version='1.2.1', reason="You should use another function")
76+
def some_old_function(x, y):
77+
return x + y
78+
79+
80+
class SomeClass(object):
81+
@deprecated(version='1.3.0', reason="This method is deprecated")
82+
def some_old_method(self, x, y):
83+
return x + y
84+
85+
86+
some_old_function(12, 34)
87+
obj = SomeClass()
88+
obj.some_old_method(5, 8)
89+
90+
91+
And Easy to Setup
92+
`````````````````
93+
94+
And run it:
95+
96+
.. code:: bash
97+
98+
$ pip install Deprecated
99+
$ python hello.py
100+
hello.py:15: DeprecationWarning: Call to deprecated function (or staticmethod) some_old_function.
101+
(You should use another function) -- Deprecated since version 1.2.0.
102+
some_old_function(12, 34)
103+
hello.py:17: DeprecationWarning: Call to deprecated method some_old_method.
104+
(This method is deprecated) -- Deprecated since version 1.3.0.
105+
obj.some_old_method(5, 8)
106+
107+
108+
You can document your code
109+
``````````````````````````
110+
111+
Have you ever wonder how to document that some functions, classes, methods, etc. are deprecated?
112+
This is now possible with the integrated Sphinx directives:
113+
114+
For instance, in hello_sphinx.py:
115+
116+
.. code:: python
117+
118+
from deprecated.sphinx import deprecated
119+
from deprecated.sphinx import versionadded
120+
from deprecated.sphinx import versionchanged
121+
122+
123+
@versionadded(version='1.0', reason="This function is new")
124+
def function_one():
125+
'''This is the function one'''
126+
127+
128+
@versionchanged(version='1.0', reason="This function is modified")
129+
def function_two():
130+
'''This is the function two'''
131+
132+
133+
@deprecated(version='1.0', reason="This function will be removed soon")
134+
def function_three():
135+
'''This is the function three'''
136+
137+
138+
function_one()
139+
function_two()
140+
function_three() # warns
141+
142+
help(function_one)
143+
help(function_two)
144+
help(function_three)
145+
146+
147+
The result it immediate
148+
```````````````````````
149+
150+
Run it:
151+
152+
.. code:: bash
153+
154+
$ python hello_sphinx.py
155+
156+
hello_sphinx.py:23: DeprecationWarning: Call to deprecated function (or staticmethod) function_three.
157+
(This function will be removed soon) -- Deprecated since version 1.0.
158+
function_three() # warns
159+
160+
Help on function function_one in module __main__:
161+
162+
function_one()
163+
This is the function one
164+
165+
.. versionadded:: 1.0
166+
This function is new
167+
168+
Help on function function_two in module __main__:
169+
170+
function_two()
171+
This is the function two
172+
173+
.. versionchanged:: 1.0
174+
This function is modified
175+
176+
Help on function function_three in module __main__:
177+
178+
function_three()
179+
This is the function three
180+
181+
.. deprecated:: 1.0
182+
This function will be removed soon
183+
184+
185+
Links
186+
`````
187+
188+
* `Python package index (PyPi) <https://pypi.org/project/Deprecated/>`_
189+
* `GitHub website <https://github.com/laurent-laporte-pro/deprecated>`_
190+
* `Read The Docs <https://readthedocs.org/projects/deprecated>`_
191+
* `EBook on Lulu.com <http://www.lulu.com/commerce/index.php?fBuyContent=21305117>`_
192+
* `StackOverFlow Q&A <https://stackoverflow.com/a/40301488/1513933>`_
193+
* `Development version
194+
<https://github.com/laurent-laporte-pro/deprecated/zipball/master#egg=Deprecated-dev>`_
195+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Deprecated-1.2.18.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
2+
Deprecated-1.2.18.dist-info/LICENSE.rst,sha256=HoPt0VvkGbXVveNy4yXlJ_9PmRX1SOfHUxS0H2aZ6Dw,1081
3+
Deprecated-1.2.18.dist-info/METADATA,sha256=4CrUw5Bl8_NsBuZYe0Nw-mIwQnVpT1CnmBYU9BqOuq8,5725
4+
Deprecated-1.2.18.dist-info/RECORD,,
5+
Deprecated-1.2.18.dist-info/WHEEL,sha256=9Hm2OB-j1QcCUq9Jguht7ayGIIZBRTdOXD1qg9cCgPM,109
6+
Deprecated-1.2.18.dist-info/top_level.txt,sha256=nHbOYawKPQQE5lQl-toUB1JBRJjUyn_m_Mb8RVJ0RjA,11
7+
deprecated/__init__.py,sha256=yZNbmDKXF4PLtp_Ikdb_9ObJLkHuFSUHvqidFTKKGFM,351
8+
deprecated/__pycache__/__init__.cpython-38.pyc,,
9+
deprecated/__pycache__/classic.cpython-38.pyc,,
10+
deprecated/__pycache__/sphinx.cpython-38.pyc,,
11+
deprecated/classic.py,sha256=7WXOt4Vf1NhrUznm8ypjS50CMyAdZwrGT58Lhb8fW14,10609
12+
deprecated/sphinx.py,sha256=cOKnXbDyFAwDr5O7HBEpgQrx-J-qfp57sfdK_LabDxs,11109
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Wheel-Version: 1.0
2+
Generator: setuptools (75.8.0)
3+
Root-Is-Purelib: true
4+
Tag: py2-none-any
5+
Tag: py3-none-any
6+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
deprecated
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pip
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Copyright (c) 2017-2021 Ingy döt Net
2+
Copyright (c) 2006-2016 Kirill Simonov
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy of
5+
this software and associated documentation files (the "Software"), to deal in
6+
the Software without restriction, including without limitation the rights to
7+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8+
of the Software, and to permit persons to whom the Software is furnished to do
9+
so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in all
12+
copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
SOFTWARE.

0 commit comments

Comments
 (0)