async def test_all_limits_are_defined(self): interface = AsgardInterface() with aioresponses() as rsps: rsps.get( f"{settings.ASGARD_API_ADDRESS}/v2/apps", status=200, payload={ "apps": [ { "id": "/test_app", "mem": "0.2", "cpus": "0.5", "labels": { "asgard.autoscale.cpu": "0.2", "asgard.autoscale.mem": "0.2", "asgard.autoscale.min_cpu_limit": "0.2", "asgard.autoscale.max_cpu_limit": "2", "asgard.autoscale.min_mem_limit": "0.2", "asgard.autoscale.max_mem_limit": "2", }, } ] }, ) apps = await interface.fetch_all_apps() self.assertEqual(1, len(apps)) self.assertEqual(0.2, apps[0].min_cpu_scale_limit) self.assertEqual(2, apps[0].max_cpu_scale_limit) self.assertEqual(0.2, apps[0].min_mem_scale_limit) self.assertEqual(2, apps[0].max_mem_scale_limit)
async def test_tune_everything_in_multiple_apps(self): interface = AsgardInterface() app1 = ScalableApp("test1") app2 = ScalableApp("test2") app3 = ScalableApp("test3") decisions = [ Decision(app1.id, cpu=0.2, mem=10), Decision(app2.id, cpu=0.4, mem=20), Decision(app3.id, cpu=0.1, mem=9), ] with aioresponses() as rsps: rsps.put( f"{settings.ASGARD_API_ADDRESS}/v2/apps", status=200, payload={ "deploymentId": "test2", "version": "1.0" }, ) applied_decisions = await interface.apply_decisions(decisions) self.assertEqual(len(applied_decisions), 3) for i in range(len(decisions)): self.assertEqual(applied_decisions[i]["id"], decisions[i].id) self.assertEqual(applied_decisions[i]["cpus"], decisions[i].cpu) self.assertEqual(applied_decisions[i]["mem"], decisions[i].mem)
async def test_get_app_stats_non_existing_app_id(self): scaler = AsgardInterface() with aioresponses() as rsps: fixture = { "stats": { "type": "ASGARD", "errors": {}, "cpu_pct": "0", "ram_pct": "0", "cpu_thr_pct": "0", } } app = ScalableApp("app_test1") rsps.get( f"{settings.ASGARD_API_ADDRESS}/apps/{app.id}/stats/avg-1min", status=200, payload=fixture, ) stats = await scaler.get_app_stats(app) self.assertEqual(None, stats) self.assertEqual(None, app.app_stats)
async def test_cpu_decision_is_rounded_to_3_decimal_places(self): interface = AsgardInterface() decisions = [Decision("test", cpu=0.436_721_072_367)] body_fixture = [{"id": "test", "cpus": 0.437}] headers_fixture = { "Content-Type": "application/json", "Authorization": f"Token {settings.AUTOSCALER_AUTH_TOKEN}", } with aioresponses() as rsps: rsps.put( f"{settings.ASGARD_API_ADDRESS}/v2/apps", status=200, payload={ "deploymentId": "test", "version": "1.0" }, ) await interface.apply_decisions(decisions) calls = rsps.requests.get( ("put", URL(f"{settings.ASGARD_API_ADDRESS}/v2/apps"))) self.assertIsNotNone(calls) self.assertEqual(body_fixture, calls[0].kwargs.get("json")) self.assertEqual( headers_fixture, interface._asgard_client._http_client.default_headers, )
async def test_get_all_apps_which_should_be_scaled_all_apps_should(self): scaler = AsgardInterface() with aioresponses() as rsps: payload = { "apps": [ { "id": "/test_app1", "cpus": "0.2", "mem": "0.2", "labels": { "asgard.autoscale.cpu": 0.3, "asgard.autoscale.mem": 0.8, }, }, { "id": "/test_app2", "cpus": "0.2", "mem": "0.2", "labels": { "asgard.autoscale.cpu": 0.1, "asgard.autoscale.mem": 0.1, }, }, { "id": "/test_app3", "cpus": "0.2", "mem": "0.2", "labels": { "asgard.autoscale.cpu": 0.5, "asgard.autoscale.mem": 0.7, }, }, ] } fixture = [ ScalableApp("test_app1", cpu_threshold=0.3, mem_threshold=0.8), ScalableApp("test_app2", cpu_threshold=0.1, mem_threshold=0.1), ScalableApp("test_app3", cpu_threshold=0.5, mem_threshold=0.7), ] rsps.get( f"{settings.ASGARD_API_ADDRESS}/v2/apps", status=200, payload=payload, ) apps = await scaler.get_all_scalable_apps() self.assertEqual(len(fixture), len(apps)) for i in range(len(fixture)): self.assertEqual(fixture[i].id, apps[i].id) self.assertEqual( fixture[i].cpu_threshold, apps[i].cpu_threshold ) self.assertEqual( fixture[i].mem_threshold, apps[i].mem_threshold )
async def test_get_app_stats_existing_app_id(self): scaler = AsgardInterface() with aioresponses() as rsps: payload = { "stats": { "type": "ASGARD", "errors": {}, "cpu_pct": "0.93", "ram_pct": "8.91", "cpu_thr_pct": "0.06", } } app = ScalableApp("app_test1") rsps.get( f"{settings.ASGARD_API_ADDRESS}/apps/{app.id}/stats/avg-1min", status=200, payload=payload, ) fixture = AppStats(cpu_usage=0.93, mem_usage=8.91) app_stats = await scaler.get_app_stats(app) self.assertEqual(fixture.cpu_usage, app_stats.cpu_usage) self.assertEqual(fixture.mem_usage, app_stats.mem_usage)
async def test_only_mem_should_not_be_scaled_mem_ignored(self): interface = AsgardInterface() with aioresponses() as rsps: rsps.get( f"{settings.ASGARD_API_ADDRESS}/v2/apps", status=200, payload={ "apps": [ { "id": "/test_app", "mem": "0.2", "cpus": "0.5", "labels": { "asgard.autoscale.cpu": "0.2", "asgard.autoscale.mem": "0.2", }, }, { "id": "/test_app2", "cpus": "0.1", "mem": "0.2", "labels": { "asgard.autoscale.cpu": "0.2", "asgard.autoscale.mem": "0.2", "asgard.autoscale.ignore": "mem", }, }, { "id": "/test_app3", "cpus": "0.1", "mem": "0.6", "labels": { "asgard.autoscale.cpu": "0.2", "asgard.autoscale.mem": "0.2", }, }, ] }, ) apps = await interface.fetch_all_apps() self.assertEqual(3, len(apps)) self.assertEqual(True, apps[0].is_set_to_scale()) self.assertEqual(True, apps[0].is_set_to_scale_cpu()) self.assertEqual(True, apps[0].is_set_to_scale_mem()) self.assertEqual(True, apps[1].is_set_to_scale()) self.assertEqual(True, apps[1].is_set_to_scale_cpu()) self.assertEqual(False, apps[1].is_set_to_scale_mem()) self.assertEqual(True, apps[2].is_set_to_scale()) self.assertEqual(True, apps[2].is_set_to_scale_cpu()) self.assertEqual(True, apps[2].is_set_to_scale_mem())
async def scale_all_apps(app: App): cloud_interface = AsgardInterface() state_checker = PeriodicStateChecker(cloud_interface) decision_maker = DecisionComponent() logger.debug({"AUTOSCALER": "iniciando autoscaler"}) apps_stats = await state_checker.get_scalable_apps_stats() logger.debug({"AUTOSCALER_FETCH_APPS": [app.id for app in apps_stats]}) scaling_decisions = decision_maker.decide_scaling_actions(apps_stats) await cloud_interface.apply_decisions(scaling_decisions)
async def test_sending_auth_in_headers(self): headers_fixture = { "Content-Type": "application/json", "Authorization": f"Token {settings.AUTOSCALER_AUTH_TOKEN}", } scaler = AsgardInterface() self.assertEqual( scaler._asgard_client._http_client.default_headers, headers_fixture )
async def test_get_all_apps_data_no_data_found(self): scaler = AsgardInterface() with aioresponses() as rsps: rsps.get( f"{settings.ASGARD_API_ADDRESS}/v2/apps", status=200, payload={"apps": []}, ) apps = await scaler.fetch_all_apps() self.assertEqual([], apps)
async def test_get_all_apps_data(self): scaler = AsgardInterface() with aioresponses() as rsps: rsps.get( f"{settings.ASGARD_API_ADDRESS}/v2/apps", status=200, payload={ "apps": [ { "id": "/test_app", "cpus": "0.1", "mem": "0.2", "labels": {}, }, { "id": "/test_app2", "cpus": "0.1", "mem": "0.2", "labels": {}, }, { "id": "/test_app3", "cpus": "0.1", "mem": "0.2", "labels": {}, }, { "id": "/test_app4", "cpus": "0.1", "mem": "0.2", "labels": {}, }, ] }, ) apps = await scaler.fetch_all_apps() fixture = [ ScalableApp("test_app"), ScalableApp("test_app2"), ScalableApp("test_app3"), ScalableApp("test_app4"), ] self.assertEqual(len(fixture), len(apps)) for i in range(len(fixture)): self.assertEqual(fixture[i].id, apps[i].id)
async def test_everything_should_be_scaled_all_apps(self): interface = AsgardInterface() with aioresponses() as rsps: rsps.get( f"{settings.ASGARD_API_ADDRESS}/v2/apps", status=200, payload={ "apps": [ { "id": "/test_app", "cpus": "0.1", "mem": "0.2", "labels": { "asgard.autoscale.cpu": "0.2", "asgard.autoscale.mem": "0.2", }, }, { "id": "/test_app2", "cpus": "0.1", "mem": "0.2", "labels": { "asgard.autoscale.cpu": "0.2", "asgard.autoscale.mem": "0.2", }, }, { "id": "/test_app3", "cpus": "0.1", "mem": "0.2", "labels": { "asgard.autoscale.cpu": "0.2", "asgard.autoscale.mem": "0.2", }, }, ] }, ) apps = await interface.fetch_all_apps() self.assertEqual(3, len(apps)) for i in range(3): self.assertEqual(True, apps[i].is_set_to_scale()) self.assertEqual(True, apps[i].is_set_to_scale_cpu()) self.assertEqual(True, apps[i].is_set_to_scale_mem())
async def test_get_all_apps_which_should_be_scaled_no_app_should(self): scaler = AsgardInterface() with aioresponses() as rsps: fixture = { "apps": [ { "id": "/test_app1", "cpus": "0.2", "mem": "0.2", "labels": { "asgard.autoscale.cpu": 0.3, "asgard.autoscale.mem": 0.8, "asgard.autoscale.ignore": "all", }, }, { "id": "/test_app2", "cpus": "0.2", "mem": "0.2", "labels": { "asgard.autoscale.cpu": 0.1, "asgard.autoscale.mem": 0.1, "asgard.autoscale.ignore": "cpu;mem", }, }, { "id": "/test_app3", "cpus": "0.2", "mem": "0.2", "labels": { "asgard.autoscale.cpu": 0.5, "asgard.autoscale.ignore": "cpu", }, }, ] } rsps.get( f"{settings.ASGARD_API_ADDRESS}/v2/apps", status=200, payload=fixture, ) apps = await scaler.get_all_scalable_apps() self.assertEqual([], apps) self.assertEqual(0, len(apps))
async def test_tune_one_thing_in_one_app(self): interface = AsgardInterface() app = ScalableApp("test") decisions = [Decision(app.id, cpu=0.3)] with aioresponses() as rsps: rsps.put( f"{settings.ASGARD_API_ADDRESS}/v2/apps", status=200, payload={ "deploymentId": "test1", "version": "1.0" }, ) applied_decisions = await interface.apply_decisions(decisions) self.assertEqual(len(applied_decisions), 1) self.assertEqual(applied_decisions[0]["id"], decisions[0].id) self.assertEqual(applied_decisions[0]["cpus"], decisions[0].cpu) self.assertEqual("mem" in applied_decisions[0], False)
async def test_tune_multiple_apps_with_different_params(self): interface = AsgardInterface() app1 = ScalableApp("test1") app2 = ScalableApp("test2") app3 = ScalableApp("test3") decisions = [ Decision(app1.id, mem=10), Decision(app2.id, cpu=0.4), Decision(app3.id, cpu=0.1, mem=9), ] with aioresponses() as rsps: rsps.put( f"{settings.ASGARD_API_ADDRESS}/v2/apps", status=200, payload={ "deploymentId": "test2", "version": "1.0" }, ) applied_decisions = await interface.apply_decisions(decisions) self.assertEqual(len(applied_decisions), 3) self.assertEqual(applied_decisions[0]["id"], decisions[0].id) self.assertEqual(applied_decisions[0]["mem"], decisions[0].mem) self.assertEqual("cpus" in applied_decisions[0], False) self.assertEqual(applied_decisions[1]["id"], decisions[1].id) self.assertEqual(applied_decisions[1]["cpus"], decisions[1].cpu) self.assertEqual("mem" in applied_decisions[1], False) self.assertEqual(applied_decisions[2]["id"], decisions[2].id) self.assertEqual(applied_decisions[2]["mem"], decisions[2].mem) self.assertEqual(applied_decisions[2]["cpus"], decisions[2].cpu)