зеркало из https://github.com/mozilla/taar.git
Fixed up all test cases that broke when merging in
srgutils.context.Context
This commit is contained in:
Родитель
b86e713227
Коммит
b4f5f6a48c
|
@ -14,11 +14,12 @@ chain.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from taar.recommenders import utils
|
from taar.recommenders import utils
|
||||||
from srgutil.context import Context
|
# Clobber the Context name to prevent messy name collisions
|
||||||
|
from srgutil.context import Context as _Context
|
||||||
|
|
||||||
|
|
||||||
def default_context():
|
def default_context():
|
||||||
ctx = Context()
|
ctx = _Context()
|
||||||
from taar.recommenders import CollaborativeRecommender
|
from taar.recommenders import CollaborativeRecommender
|
||||||
from taar.recommenders import SimilarityRecommender
|
from taar.recommenders import SimilarityRecommender
|
||||||
from taar.recommenders import LocaleRecommender
|
from taar.recommenders import LocaleRecommender
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
|
|
||||||
from taar.adapters.dynamo import ProfileController
|
|
||||||
import boto3
|
|
||||||
import zlib
|
|
||||||
import json
|
|
||||||
|
|
||||||
|
|
||||||
def test_crashy_profile_controller(monkeypatch):
|
|
||||||
def mock_boto3_resource(*args, **kwargs):
|
|
||||||
class ExceptionRaisingMockTable:
|
|
||||||
def __init__(self, tbl_name):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_item(self, *args, **kwargs):
|
|
||||||
raise Exception
|
|
||||||
|
|
||||||
class MockDDB:
|
|
||||||
pass
|
|
||||||
mock_ddb = MockDDB()
|
|
||||||
mock_ddb.Table = ExceptionRaisingMockTable
|
|
||||||
return mock_ddb
|
|
||||||
|
|
||||||
monkeypatch.setattr(boto3, 'resource', mock_boto3_resource)
|
|
||||||
|
|
||||||
pc = ProfileController('us-west-2', 'taar_addon_data_20180206')
|
|
||||||
assert pc.get_client_profile("exception_raising_client_id") is None
|
|
||||||
|
|
||||||
|
|
||||||
def test_profile_controller(monkeypatch):
|
|
||||||
def mock_boto3_resource(*args, **kwargs):
|
|
||||||
some_bytes = zlib.compress(json.dumps({'key': "with_some_data"}).encode('utf8'))
|
|
||||||
|
|
||||||
class ValueObj:
|
|
||||||
value = some_bytes
|
|
||||||
|
|
||||||
class MockTable:
|
|
||||||
def __init__(self, tbl_name):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_item(self, *args, **kwargs):
|
|
||||||
value_obj = ValueObj()
|
|
||||||
response = {'Item': {'json_payload': value_obj}}
|
|
||||||
return response
|
|
||||||
|
|
||||||
class MockDDB:
|
|
||||||
pass
|
|
||||||
mock_ddb = MockDDB()
|
|
||||||
mock_ddb.Table = MockTable
|
|
||||||
return mock_ddb
|
|
||||||
|
|
||||||
monkeypatch.setattr(boto3, 'resource', mock_boto3_resource)
|
|
||||||
|
|
||||||
pc = ProfileController('us-west-2', 'taar_addon_data_20180206')
|
|
||||||
jdata = pc.get_client_profile("exception_raising_client_id")
|
|
||||||
assert jdata == {'key': 'with_some_data'}
|
|
|
@ -1,6 +1,5 @@
|
||||||
from taar.cache import Clock, JSONCache
|
from taar.cache import Clock, JSONCache
|
||||||
import time
|
import time
|
||||||
from taar.context import Context
|
|
||||||
|
|
||||||
|
|
||||||
EXPECTED_JSON = {"foo": 42}
|
EXPECTED_JSON = {"foo": 42}
|
||||||
|
@ -30,9 +29,9 @@ def test_clock():
|
||||||
assert abs(actual - expected) < 0.1
|
assert abs(actual - expected) < 0.1
|
||||||
|
|
||||||
|
|
||||||
def test_fetch_json():
|
def test_fetch_json(test_ctx):
|
||||||
""" Just test a URL that we know will fail """
|
""" Just test a URL that we know will fail """
|
||||||
ctx = Context()
|
ctx = test_ctx
|
||||||
ctx['utils'] = utils = MockUtils()
|
ctx['utils'] = utils = MockUtils()
|
||||||
ctx['clock'] = Clock()
|
ctx['clock'] = Clock()
|
||||||
cache = JSONCache(ctx)
|
cache = JSONCache(ctx)
|
||||||
|
@ -45,9 +44,9 @@ def test_fetch_json():
|
||||||
assert utils._fetch_count == 1
|
assert utils._fetch_count == 1
|
||||||
|
|
||||||
|
|
||||||
def test_get_s3_json_content():
|
def test_get_s3_json_content(test_ctx):
|
||||||
""" Just test an S3 bucket and key that doesn't exist """
|
""" Just test an S3 bucket and key that doesn't exist """
|
||||||
ctx = Context()
|
ctx = test_ctx
|
||||||
ctx['utils'] = utils = MockUtils()
|
ctx['utils'] = utils = MockUtils()
|
||||||
ctx['clock'] = Clock()
|
ctx['clock'] = Clock()
|
||||||
cache = JSONCache(ctx)
|
cache = JSONCache(ctx)
|
||||||
|
@ -60,7 +59,7 @@ def test_get_s3_json_content():
|
||||||
assert utils._get_count == 1
|
assert utils._get_count == 1
|
||||||
|
|
||||||
|
|
||||||
def test_expiry():
|
def test_expiry(test_ctx):
|
||||||
""" Just test a URL that we know will fail """
|
""" Just test a URL that we know will fail """
|
||||||
class MockClock:
|
class MockClock:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -69,7 +68,7 @@ def test_expiry():
|
||||||
def time(self):
|
def time(self):
|
||||||
return self._now
|
return self._now
|
||||||
|
|
||||||
ctx = Context()
|
ctx = test_ctx
|
||||||
utils = MockUtils()
|
utils = MockUtils()
|
||||||
ctx['utils'] = utils
|
ctx['utils'] = utils
|
||||||
ctx['clock'] = MockClock()
|
ctx['clock'] = MockClock()
|
||||||
|
|
|
@ -4,16 +4,15 @@ Test cases for the TAAR CollaborativeRecommender
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
|
|
||||||
from taar.context import Context
|
|
||||||
from taar.cache import JSONCache, Clock
|
from taar.cache import JSONCache, Clock
|
||||||
|
|
||||||
from taar.recommenders.collaborative_recommender import ADDON_MAPPING_URL
|
from taar.recommenders.collaborative_recommender import ADDON_MAPPING_URL
|
||||||
from taar.recommenders.collaborative_recommender import ADDON_MODEL_URL
|
from taar.recommenders.collaborative_recommender import ADDON_MODEL_URL
|
||||||
|
|
||||||
|
|
||||||
from taar.recommenders.collaborative_recommender import CollaborativeRecommender
|
from taar.recommenders.collaborative_recommender import CollaborativeRecommender
|
||||||
from taar.recommenders.collaborative_recommender import positive_hash
|
from taar.recommenders.collaborative_recommender import positive_hash
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
"""
|
"""
|
||||||
We need to generate a synthetic list of addons and relative weights
|
We need to generate a synthetic list of addons and relative weights
|
||||||
for co-occurance. It's important to note that the
|
for co-occurance. It's important to note that the
|
||||||
|
@ -87,8 +86,8 @@ def activate_responses(ctx):
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
def test_can_recommend():
|
def test_can_recommend(mocked_ctx):
|
||||||
ctx = get_mocked_ctx()
|
ctx = mocked_ctx
|
||||||
r = CollaborativeRecommender(ctx)
|
r = CollaborativeRecommender(ctx)
|
||||||
|
|
||||||
# Test that we can't recommend if we have not enough client info.
|
# Test that we can't recommend if we have not enough client info.
|
||||||
|
@ -100,20 +99,20 @@ def test_can_recommend():
|
||||||
"client_id": "test-client"})
|
"client_id": "test-client"})
|
||||||
|
|
||||||
|
|
||||||
def get_error_ctx():
|
@pytest.fixture
|
||||||
ctx = Context()
|
def error_ctx(test_ctx):
|
||||||
ctx = activate_error_responses(ctx)
|
ctx = activate_error_responses(test_ctx)
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
def get_mocked_ctx():
|
@pytest.fixture
|
||||||
ctx = Context()
|
def mocked_ctx(test_ctx):
|
||||||
ctx = activate_responses(ctx)
|
ctx = activate_responses(test_ctx)
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
def test_can_recommend_no_model():
|
def test_can_recommend_no_model(error_ctx):
|
||||||
ctx = get_error_ctx()
|
ctx = error_ctx
|
||||||
r = CollaborativeRecommender(ctx)
|
r = CollaborativeRecommender(ctx)
|
||||||
|
|
||||||
# We should never be able to recommend if something went wrong with the model.
|
# We should never be able to recommend if something went wrong with the model.
|
||||||
|
@ -122,10 +121,10 @@ def test_can_recommend_no_model():
|
||||||
assert not r.can_recommend({"installed_addons": ["uBlock0@raymondhill.net"]})
|
assert not r.can_recommend({"installed_addons": ["uBlock0@raymondhill.net"]})
|
||||||
|
|
||||||
|
|
||||||
def test_empty_recommendations():
|
def test_empty_recommendations(mocked_ctx):
|
||||||
# Tests that the empty recommender always recommends an empty list
|
# Tests that the empty recommender always recommends an empty list
|
||||||
# of addons if we have no addons
|
# of addons if we have no addons
|
||||||
ctx = get_mocked_ctx()
|
ctx = mocked_ctx
|
||||||
r = CollaborativeRecommender(ctx)
|
r = CollaborativeRecommender(ctx)
|
||||||
assert not r.can_recommend({})
|
assert not r.can_recommend({})
|
||||||
|
|
||||||
|
@ -133,10 +132,10 @@ def test_empty_recommendations():
|
||||||
# defined.
|
# defined.
|
||||||
|
|
||||||
|
|
||||||
def test_best_recommendation():
|
def test_best_recommendation(mocked_ctx):
|
||||||
# Make sure the structure of the recommendations is correct and that we
|
# Make sure the structure of the recommendations is correct and that we
|
||||||
# recommended the the right addon.
|
# recommended the the right addon.
|
||||||
ctx = get_mocked_ctx()
|
ctx = mocked_ctx
|
||||||
r = CollaborativeRecommender(ctx)
|
r = CollaborativeRecommender(ctx)
|
||||||
|
|
||||||
# An non-empty set of addons should give a list of recommendations
|
# An non-empty set of addons should give a list of recommendations
|
||||||
|
@ -158,11 +157,11 @@ def test_best_recommendation():
|
||||||
assert numpy.isclose(result[1], numpy.float64('0.3225'))
|
assert numpy.isclose(result[1], numpy.float64('0.3225'))
|
||||||
|
|
||||||
|
|
||||||
def test_recommendation_weights():
|
def test_recommendation_weights(mocked_ctx):
|
||||||
"""
|
"""
|
||||||
Weights should be ordered greatest to lowest
|
Weights should be ordered greatest to lowest
|
||||||
"""
|
"""
|
||||||
ctx = get_mocked_ctx()
|
ctx = mocked_ctx
|
||||||
r = CollaborativeRecommender(ctx)
|
r = CollaborativeRecommender(ctx)
|
||||||
|
|
||||||
# An non-empty set of addons should give a list of recommendations
|
# An non-empty set of addons should give a list of recommendations
|
||||||
|
@ -192,11 +191,11 @@ def test_recommendation_weights():
|
||||||
assert numpy.isclose(result[1], numpy.float64('0.29'))
|
assert numpy.isclose(result[1], numpy.float64('0.29'))
|
||||||
|
|
||||||
|
|
||||||
def test_recommender_str():
|
def test_recommender_str(mocked_ctx):
|
||||||
"""Tests that the string representation of the recommender is correct
|
"""Tests that the string representation of the recommender is correct
|
||||||
"""
|
"""
|
||||||
# TODO: this test is brittle and should be removed once it is safe
|
# TODO: this test is brittle and should be removed once it is safe
|
||||||
# to do so
|
# to do so
|
||||||
ctx = get_mocked_ctx()
|
ctx = mocked_ctx
|
||||||
r = CollaborativeRecommender(ctx)
|
r = CollaborativeRecommender(ctx)
|
||||||
assert str(r) == "CollaborativeRecommender"
|
assert str(r) == "CollaborativeRecommender"
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
from taar.context import Context
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
from taar.cache import JSONCache, Clock
|
from taar.cache import JSONCache, Clock
|
||||||
|
|
||||||
from taar.recommenders.ensemble_recommender import WeightCache, EnsembleRecommender
|
from taar.recommenders.ensemble_recommender import WeightCache, EnsembleRecommender
|
||||||
|
@ -14,9 +17,8 @@ class Mocker:
|
||||||
return {'ensemble_weights': EXPECTED}
|
return {'ensemble_weights': EXPECTED}
|
||||||
|
|
||||||
|
|
||||||
def test_weight_cache(): # noqa
|
def test_weight_cache(test_ctx): # noqa
|
||||||
|
ctx = test_ctx
|
||||||
ctx = Context()
|
|
||||||
ctx['utils'] = Mocker()
|
ctx['utils'] = Mocker()
|
||||||
ctx['clock'] = Clock()
|
ctx['clock'] = Clock()
|
||||||
ctx['cache'] = JSONCache(ctx)
|
ctx['cache'] = JSONCache(ctx)
|
||||||
|
@ -26,8 +28,8 @@ def test_weight_cache(): # noqa
|
||||||
assert EXPECTED == actual
|
assert EXPECTED == actual
|
||||||
|
|
||||||
|
|
||||||
def test_recommendations():
|
def test_recommendations(test_ctx):
|
||||||
ctx = Context()
|
ctx = test_ctx
|
||||||
|
|
||||||
ctx['utils'] = Mocker()
|
ctx['utils'] = Mocker()
|
||||||
ctx['clock'] = Clock()
|
ctx['clock'] = Clock()
|
||||||
|
@ -53,8 +55,8 @@ def test_recommendations():
|
||||||
assert recommendation_list == EXPECTED_RESULTS
|
assert recommendation_list == EXPECTED_RESULTS
|
||||||
|
|
||||||
|
|
||||||
def test_preinstalled_guids():
|
def test_preinstalled_guids(test_ctx):
|
||||||
ctx = Context()
|
ctx = test_ctx
|
||||||
|
|
||||||
ctx['utils'] = Mocker()
|
ctx['utils'] = Mocker()
|
||||||
ctx['clock'] = Clock()
|
ctx['clock'] = Clock()
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
import pytest
|
import pytest
|
||||||
from taar.context import default_context
|
from taar.context import default_context
|
||||||
from taar import ProfileController, ProfileFetcher
|
from taar import ProfileFetcher
|
||||||
|
from taar.profile_fetcher import ProfileController
|
||||||
from taar import recommenders
|
from taar import recommenders
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
||||||
def create_recommendation_manager():
|
def create_recommendation_manager():
|
||||||
root_ctx = default_context()
|
root_ctx = default_context()
|
||||||
client = ProfileController('us-west-2', 'taar_addon_data_20180206')
|
pf = ProfileFetcher(root_ctx)
|
||||||
pf = ProfileFetcher(client)
|
pf.set_client(ProfileController(root_ctx, 'us-west-2', 'taar_addon_data_20180206'))
|
||||||
root_ctx['profile_fetcher'] = pf
|
root_ctx['profile_fetcher'] = pf
|
||||||
r_factory = recommenders.RecommenderFactory(root_ctx.child())
|
r_factory = recommenders.RecommenderFactory(root_ctx.child())
|
||||||
root_ctx['recommender_factory'] = r_factory
|
root_ctx['recommender_factory'] = r_factory
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
from taar.context import Context
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
import pytest
|
||||||
from taar.cache import JSONCache, Clock
|
from taar.cache import JSONCache, Clock
|
||||||
|
|
||||||
from taar.recommenders import LocaleRecommender
|
from taar.recommenders import LocaleRecommender
|
||||||
|
@ -20,16 +24,17 @@ class MockUtils:
|
||||||
return FAKE_LOCALE_DATA
|
return FAKE_LOCALE_DATA
|
||||||
|
|
||||||
|
|
||||||
def create_test_ctx():
|
@pytest.fixture
|
||||||
ctx = Context()
|
def my_context(test_ctx):
|
||||||
|
ctx = test_ctx
|
||||||
ctx['utils'] = MockUtils()
|
ctx['utils'] = MockUtils()
|
||||||
ctx['clock'] = Clock()
|
ctx['clock'] = Clock()
|
||||||
ctx['cache'] = JSONCache(ctx)
|
ctx['cache'] = JSONCache(ctx)
|
||||||
return ctx.child()
|
return ctx.child()
|
||||||
|
|
||||||
|
|
||||||
def test_can_recommend():
|
def test_can_recommend(my_context):
|
||||||
ctx = create_test_ctx()
|
ctx = my_context
|
||||||
r = LocaleRecommender(ctx)
|
r = LocaleRecommender(ctx)
|
||||||
|
|
||||||
# Test that we can't recommend if we have not enough client info.
|
# Test that we can't recommend if we have not enough client info.
|
||||||
|
@ -40,8 +45,8 @@ def test_can_recommend():
|
||||||
assert r.can_recommend({"locale": "en"})
|
assert r.can_recommend({"locale": "en"})
|
||||||
|
|
||||||
|
|
||||||
def test_can_recommend_no_model():
|
def test_can_recommend_no_model(my_context):
|
||||||
ctx = create_test_ctx()
|
ctx = my_context
|
||||||
r = LocaleRecommender(ctx)
|
r = LocaleRecommender(ctx)
|
||||||
|
|
||||||
# We should never be able to recommend if something went
|
# We should never be able to recommend if something went
|
||||||
|
@ -51,14 +56,14 @@ def test_can_recommend_no_model():
|
||||||
assert not r.can_recommend({"locale": "it"})
|
assert not r.can_recommend({"locale": "it"})
|
||||||
|
|
||||||
|
|
||||||
def test_recommendations():
|
def test_recommendations(my_context):
|
||||||
"""Test that the locale recommender returns the correct
|
"""Test that the locale recommender returns the correct
|
||||||
locale dependent addons.
|
locale dependent addons.
|
||||||
|
|
||||||
The JSON output for this recommender should be a list of 2-tuples
|
The JSON output for this recommender should be a list of 2-tuples
|
||||||
of (GUID, weight).
|
of (GUID, weight).
|
||||||
"""
|
"""
|
||||||
ctx = create_test_ctx()
|
ctx = my_context
|
||||||
r = LocaleRecommender(ctx)
|
r = LocaleRecommender(ctx)
|
||||||
recommendations = r.recommend({"locale": "en"}, 10)
|
recommendations = r.recommend({"locale": "en"}, 10)
|
||||||
|
|
||||||
|
@ -73,17 +78,17 @@ def test_recommendations():
|
||||||
assert addon_id in FAKE_LOCALE_DATA["en"]
|
assert addon_id in FAKE_LOCALE_DATA["en"]
|
||||||
|
|
||||||
|
|
||||||
def test_recommender_str():
|
def test_recommender_str(my_context):
|
||||||
"""Tests that the string representation of the recommender is correct
|
"""Tests that the string representation of the recommender is correct
|
||||||
"""
|
"""
|
||||||
# TODO: this test is brittle and should be removed once it is safe
|
# TODO: this test is brittle and should be removed once it is safe
|
||||||
# to do so
|
# to do so
|
||||||
ctx = create_test_ctx()
|
ctx = my_context
|
||||||
r = LocaleRecommender(ctx)
|
r = LocaleRecommender(ctx)
|
||||||
assert str(r) == "LocaleRecommender"
|
assert str(r) == "LocaleRecommender"
|
||||||
|
|
||||||
|
|
||||||
def test_recommender_extra_data():
|
def test_recommender_extra_data(my_context):
|
||||||
# Test that the recommender uses locale data from the "extra"
|
# Test that the recommender uses locale data from the "extra"
|
||||||
# section if available.
|
# section if available.
|
||||||
def validate_recommendations(data, expected_locale):
|
def validate_recommendations(data, expected_locale):
|
||||||
|
@ -97,7 +102,7 @@ def test_recommender_extra_data():
|
||||||
assert addon_id in FAKE_LOCALE_DATA[expected_locale]
|
assert addon_id in FAKE_LOCALE_DATA[expected_locale]
|
||||||
assert 1 == weight
|
assert 1 == weight
|
||||||
|
|
||||||
ctx = create_test_ctx()
|
ctx = my_context
|
||||||
r = LocaleRecommender(ctx)
|
r = LocaleRecommender(ctx)
|
||||||
recommendations = r.recommend({}, 10, extra_data={"locale": "en"})
|
recommendations = r.recommend({}, 10, extra_data={"locale": "en"})
|
||||||
validate_recommendations(recommendations, "en")
|
validate_recommendations(recommendations, "en")
|
||||||
|
|
|
@ -1,5 +1,13 @@
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
from taar import ProfileFetcher
|
from taar import ProfileFetcher
|
||||||
|
from taar.profile_fetcher import ProfileController
|
||||||
|
import boto3
|
||||||
import copy
|
import copy
|
||||||
|
import json
|
||||||
|
import zlib
|
||||||
|
|
||||||
|
|
||||||
class MockProfileController:
|
class MockProfileController:
|
||||||
|
@ -66,3 +74,53 @@ def test_dont_crash_without_active_addons(test_ctx):
|
||||||
expected = copy.deepcopy(MOCK_DATA['expected_result'])
|
expected = copy.deepcopy(MOCK_DATA['expected_result'])
|
||||||
expected['installed_addons'][:] = []
|
expected['installed_addons'][:] = []
|
||||||
assert fetcher.get("random-client-id") == expected
|
assert fetcher.get("random-client-id") == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_crashy_profile_controller(test_ctx, monkeypatch):
|
||||||
|
def mock_boto3_resource(*args, **kwargs):
|
||||||
|
class ExceptionRaisingMockTable:
|
||||||
|
def __init__(self, tbl_name):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_item(self, *args, **kwargs):
|
||||||
|
raise Exception
|
||||||
|
|
||||||
|
class MockDDB:
|
||||||
|
pass
|
||||||
|
mock_ddb = MockDDB()
|
||||||
|
mock_ddb.Table = ExceptionRaisingMockTable
|
||||||
|
return mock_ddb
|
||||||
|
|
||||||
|
monkeypatch.setattr(boto3, 'resource', mock_boto3_resource)
|
||||||
|
|
||||||
|
pc = ProfileController(test_ctx, 'us-west-2', 'taar_addon_data_20180206')
|
||||||
|
assert pc.get_client_profile("exception_raising_client_id") is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_profile_controller(test_ctx, monkeypatch):
|
||||||
|
def mock_boto3_resource(*args, **kwargs):
|
||||||
|
some_bytes = zlib.compress(json.dumps({'key': "with_some_data"}).encode('utf8'))
|
||||||
|
|
||||||
|
class ValueObj:
|
||||||
|
value = some_bytes
|
||||||
|
|
||||||
|
class MockTable:
|
||||||
|
def __init__(self, tbl_name):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_item(self, *args, **kwargs):
|
||||||
|
value_obj = ValueObj()
|
||||||
|
response = {'Item': {'json_payload': value_obj}}
|
||||||
|
return response
|
||||||
|
|
||||||
|
class MockDDB:
|
||||||
|
pass
|
||||||
|
mock_ddb = MockDDB()
|
||||||
|
mock_ddb.Table = MockTable
|
||||||
|
return mock_ddb
|
||||||
|
|
||||||
|
monkeypatch.setattr(boto3, 'resource', mock_boto3_resource)
|
||||||
|
|
||||||
|
pc = ProfileController(test_ctx, 'us-west-2', 'taar_addon_data_20180206')
|
||||||
|
jdata = pc.get_client_profile("exception_raising_client_id")
|
||||||
|
assert jdata == {'key': 'with_some_data'}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
from taar.context import Context
|
|
||||||
from taar.cache import JSONCache, Clock
|
from taar.cache import JSONCache, Clock
|
||||||
|
|
||||||
from taar.profile_fetcher import ProfileFetcher
|
from taar.profile_fetcher import ProfileFetcher
|
||||||
|
@ -29,10 +28,13 @@ class StubRecommender(AbstractRecommender):
|
||||||
return self._recommendations
|
return self._recommendations
|
||||||
|
|
||||||
|
|
||||||
def get_test_ctx():
|
@pytest.fixture
|
||||||
fetcher = ProfileFetcher(MockProfileController(None))
|
def my_context(test_ctx):
|
||||||
|
ctx = test_ctx
|
||||||
|
|
||||||
|
fetcher = ProfileFetcher(ctx)
|
||||||
|
fetcher.set_client(MockProfileController(None))
|
||||||
factory = MockRecommenderFactory()
|
factory = MockRecommenderFactory()
|
||||||
ctx = Context()
|
|
||||||
ctx['profile_fetcher'] = fetcher
|
ctx['profile_fetcher'] = fetcher
|
||||||
ctx['recommender_factory'] = factory
|
ctx['recommender_factory'] = factory
|
||||||
|
|
||||||
|
@ -42,8 +44,8 @@ def get_test_ctx():
|
||||||
return ctx.child()
|
return ctx.child()
|
||||||
|
|
||||||
|
|
||||||
def test_none_profile_returns_empty_list():
|
def test_none_profile_returns_empty_list(my_context):
|
||||||
ctx = get_test_ctx()
|
ctx = my_context
|
||||||
ctx['clock'] = Clock()
|
ctx['clock'] = Clock()
|
||||||
ctx['cache'] = JSONCache(ctx)
|
ctx['cache'] = JSONCache(ctx)
|
||||||
rec_manager = RecommendationManager(ctx)
|
rec_manager = RecommendationManager(ctx)
|
||||||
|
@ -58,8 +60,8 @@ def test_intervention_b():
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_recommendations_via_manager(): # noqa
|
def test_recommendations_via_manager(my_context): # noqa
|
||||||
ctx = get_test_ctx()
|
ctx = my_context
|
||||||
|
|
||||||
EXPECTED_RESULTS = [('ghi', 3430.0),
|
EXPECTED_RESULTS = [('ghi', 3430.0),
|
||||||
('def', 3320.0),
|
('def', 3320.0),
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
import json
|
import json
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
import pytest
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import scipy.stats
|
import scipy.stats
|
||||||
|
|
||||||
from taar.context import Context
|
|
||||||
from taar.cache import JSONCache, Clock
|
from taar.cache import JSONCache, Clock
|
||||||
|
|
||||||
from taar.recommenders.similarity_recommender import \
|
from taar.recommenders.similarity_recommender import \
|
||||||
|
@ -84,25 +84,27 @@ class MockContinuousData:
|
||||||
return self.lrs_data
|
return self.lrs_data
|
||||||
|
|
||||||
|
|
||||||
def create_cat_test_ctx():
|
@pytest.fixture
|
||||||
ctx = Context()
|
def cat_test_ctx(test_ctx):
|
||||||
|
ctx = test_ctx
|
||||||
ctx['utils'] = MockCategoricalData()
|
ctx['utils'] = MockCategoricalData()
|
||||||
ctx['clock'] = Clock()
|
ctx['clock'] = Clock()
|
||||||
ctx['cache'] = JSONCache(ctx)
|
ctx['cache'] = JSONCache(ctx)
|
||||||
return ctx.child()
|
return ctx.child()
|
||||||
|
|
||||||
|
|
||||||
def create_cts_test_ctx():
|
@pytest.fixture
|
||||||
ctx = Context()
|
def cts_test_ctx(test_ctx):
|
||||||
|
ctx = test_ctx
|
||||||
ctx['utils'] = MockContinuousData()
|
ctx['utils'] = MockContinuousData()
|
||||||
ctx['clock'] = Clock()
|
ctx['clock'] = Clock()
|
||||||
ctx['cache'] = JSONCache(ctx)
|
ctx['cache'] = JSONCache(ctx)
|
||||||
return ctx.child()
|
return ctx.child()
|
||||||
|
|
||||||
|
|
||||||
def test_soft_fail():
|
def test_soft_fail(test_ctx):
|
||||||
# Create a new instance of a SimilarityRecommender.
|
# Create a new instance of a SimilarityRecommender.
|
||||||
ctx = Context()
|
ctx = test_ctx
|
||||||
ctx['utils'] = MockNoDataUtils()
|
ctx['utils'] = MockNoDataUtils()
|
||||||
ctx['clock'] = Clock()
|
ctx['clock'] = Clock()
|
||||||
ctx['cache'] = JSONCache(ctx)
|
ctx['cache'] = JSONCache(ctx)
|
||||||
|
@ -112,9 +114,9 @@ def test_soft_fail():
|
||||||
assert not r.can_recommend({})
|
assert not r.can_recommend({})
|
||||||
|
|
||||||
|
|
||||||
def test_can_recommend():
|
def test_can_recommend(cts_test_ctx):
|
||||||
# Create a new instance of a SimilarityRecommender.
|
# Create a new instance of a SimilarityRecommender.
|
||||||
ctx = create_cts_test_ctx()
|
ctx = cts_test_ctx
|
||||||
r = SimilarityRecommender(ctx)
|
r = SimilarityRecommender(ctx)
|
||||||
|
|
||||||
# Test that we can't recommend if we have not enough client info.
|
# Test that we can't recommend if we have not enough client info.
|
||||||
|
@ -138,9 +140,9 @@ def test_can_recommend():
|
||||||
assert not r.can_recommend(profile_without_x)
|
assert not r.can_recommend(profile_without_x)
|
||||||
|
|
||||||
|
|
||||||
def test_recommendations():
|
def test_recommendations(cts_test_ctx):
|
||||||
# Create a new instance of a SimilarityRecommender.
|
# Create a new instance of a SimilarityRecommender.
|
||||||
ctx = create_cts_test_ctx()
|
ctx = cts_test_ctx
|
||||||
r = SimilarityRecommender(ctx)
|
r = SimilarityRecommender(ctx)
|
||||||
|
|
||||||
# TODO: clobber the SimilarityRecommender::lr_curves
|
# TODO: clobber the SimilarityRecommender::lr_curves
|
||||||
|
@ -157,25 +159,25 @@ def test_recommendations():
|
||||||
assert type(weight) == np.float64
|
assert type(weight) == np.float64
|
||||||
|
|
||||||
|
|
||||||
def test_recommender_str():
|
def test_recommender_str(cts_test_ctx):
|
||||||
# Tests that the string representation of the recommender is correct.
|
# Tests that the string representation of the recommender is correct.
|
||||||
ctx = create_cts_test_ctx()
|
ctx = cts_test_ctx
|
||||||
r = SimilarityRecommender(ctx)
|
r = SimilarityRecommender(ctx)
|
||||||
assert str(r) == "SimilarityRecommender"
|
assert str(r) == "SimilarityRecommender"
|
||||||
|
|
||||||
|
|
||||||
def test_get_lr():
|
def test_get_lr(cts_test_ctx):
|
||||||
# Tests that the likelihood ratio values are not empty for extreme values and are realistic.
|
# Tests that the likelihood ratio values are not empty for extreme values and are realistic.
|
||||||
ctx = create_cts_test_ctx()
|
ctx = cts_test_ctx
|
||||||
r = SimilarityRecommender(ctx)
|
r = SimilarityRecommender(ctx)
|
||||||
assert r.get_lr(0.0001) is not None
|
assert r.get_lr(0.0001) is not None
|
||||||
assert r.get_lr(10.0) is not None
|
assert r.get_lr(10.0) is not None
|
||||||
assert r.get_lr(0.001) > r.get_lr(5.0)
|
assert r.get_lr(0.001) > r.get_lr(5.0)
|
||||||
|
|
||||||
|
|
||||||
def test_compute_clients_dist():
|
def test_compute_clients_dist(cts_test_ctx):
|
||||||
# Test the distance function computation.
|
# Test the distance function computation.
|
||||||
ctx = create_cts_test_ctx()
|
ctx = cts_test_ctx
|
||||||
r = SimilarityRecommender(ctx)
|
r = SimilarityRecommender(ctx)
|
||||||
test_clients = [
|
test_clients = [
|
||||||
{
|
{
|
||||||
|
@ -227,9 +229,9 @@ def test_compute_clients_dist():
|
||||||
assert per_client_test[0] >= per_client_test[1] >= per_client_test[2]
|
assert per_client_test[0] >= per_client_test[1] >= per_client_test[2]
|
||||||
|
|
||||||
|
|
||||||
def test_distance_functions():
|
def test_distance_functions(cts_test_ctx):
|
||||||
# Tests the similarity functions via expected output when passing modified client data.
|
# Tests the similarity functions via expected output when passing modified client data.
|
||||||
ctx = create_cts_test_ctx()
|
ctx = cts_test_ctx
|
||||||
r = SimilarityRecommender(ctx)
|
r = SimilarityRecommender(ctx)
|
||||||
|
|
||||||
# Generate a fake client.
|
# Generate a fake client.
|
||||||
|
@ -269,9 +271,9 @@ def test_distance_functions():
|
||||||
assert abs((j_c + 0.01) * j_d) != 0.0
|
assert abs((j_c + 0.01) * j_d) != 0.0
|
||||||
|
|
||||||
|
|
||||||
def test_weights_continuous():
|
def test_weights_continuous(cts_test_ctx):
|
||||||
# Create a new instance of a SimilarityRecommender.
|
# Create a new instance of a SimilarityRecommender.
|
||||||
ctx = create_cts_test_ctx()
|
ctx = cts_test_ctx
|
||||||
r = SimilarityRecommender(ctx)
|
r = SimilarityRecommender(ctx)
|
||||||
|
|
||||||
# In the ensemble method recommendations should be a sorted list of tuples
|
# In the ensemble method recommendations should be a sorted list of tuples
|
||||||
|
@ -301,7 +303,7 @@ def test_weights_continuous():
|
||||||
assert rec0_weight > rec1_weight > 1.0
|
assert rec0_weight > rec1_weight > 1.0
|
||||||
|
|
||||||
|
|
||||||
def test_weights_categorical():
|
def test_weights_categorical(cat_test_ctx, cts_test_ctx):
|
||||||
'''
|
'''
|
||||||
This should get :
|
This should get :
|
||||||
["{test-guid-1}", "{test-guid-2}", "{test-guid-3}", "{test-guid-4}"],
|
["{test-guid-1}", "{test-guid-2}", "{test-guid-3}", "{test-guid-4}"],
|
||||||
|
@ -311,8 +313,8 @@ def test_weights_categorical():
|
||||||
|
|
||||||
'''
|
'''
|
||||||
# Create a new instance of a SimilarityRecommender.
|
# Create a new instance of a SimilarityRecommender.
|
||||||
ctx = create_cat_test_ctx()
|
ctx = cat_test_ctx
|
||||||
ctx2 = create_cts_test_ctx()
|
ctx2 = cts_test_ctx
|
||||||
wrapped = ctx2.wrap(ctx)
|
wrapped = ctx2.wrap(ctx)
|
||||||
r = SimilarityRecommender(wrapped)
|
r = SimilarityRecommender(wrapped)
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче