import tempfile import unittest from pathlib import Path from unittest.mock import Mock from .server.http import Gateway, RequestError from .runtime import BrowserRuntimeError, NativeRuntimeManager, RuntimeRecord, validate_runtime_input from . import test_runtime as helpers class MemoryUnits(helpers.FakeUnits): def __init__(self): super().__init__() self.limits = {} self.start_count = 0 def start(self, unit, args, **limits): self.limits[unit] = limits['limits'] self.start_count += 1 return super().start(unit, args, **limits) class EnvironmentMemoryTests(unittest.TestCase): def test_start_route_forwards_memory_separately_from_generation(self): gateway=object.__new__(Gateway);gateway.runtimes=Mock() generation={'runtime_id':'a'*64,'network_id':'native-'+'b'*32,'binding_version':1} gateway.change_state('account','start',dict(generation,memory_limit_mb=4096)) gateway.runtimes.change_state.assert_called_once_with('account','start',generation,memory_limit_mb=4096) with self.assertRaises(RequestError):gateway.change_state('account','stop',dict(generation,memory_limit_mb=4096)) with self.assertRaises(BrowserRuntimeError):gateway.change_state('account','start',dict(generation,memory_limit_mb=0)) def manager(self, root, units): manager=NativeRuntimeManager(state_dir=Path(root)/'state',profile_root=Path(root)/'profiles',node_id='node-a',browser_path='/bin/true',unit_manager=units,min_free_bytes=0,display_start=1000,display_end=1010) manager._wait_for_display=lambda record:None manager._wait_for_cdp=lambda record:None manager._ready=lambda record:True self.addCleanup(manager.close) return manager def test_memory_default_and_input_validation(self): value = helpers.NativeRuntimeManagerTests().payload() validate_runtime_input(value) self.assertEqual(value['memory_limit_mb'], 2048) for limit in [512, 2048, 3072, 65536]: value = helpers.NativeRuntimeManagerTests().payload();value['memory_limit_mb'] = limit validate_runtime_input(value) self.assertEqual(value['memory_limit_mb'], limit) for limit in [0, -1, 511, 65537, True, '2048', 2.5]: value = helpers.NativeRuntimeManagerTests().payload();value['memory_limit_mb'] = limit with self.assertRaises(BrowserRuntimeError): validate_runtime_input(value) def test_custom_limit_reaches_systemd_and_metadata(self): with tempfile.TemporaryDirectory() as root: units=MemoryUnits();manager=self.manager(root,units) value=helpers.NativeRuntimeManagerTests().payload();value['memory_limit_mb']=3072 result=manager.create(value) self.assertEqual(units.limits[manager._records()[0].browser_unit]['MemoryMax'],'3072M') self.assertEqual(result['memory_limit_mb'],3072) loaded=manager._records()[0] self.assertEqual(loaded.memory_limit_mb,3072) self.assertEqual(RuntimeRecord.from_dict(loaded.to_dict()).memory_limit_mb,3072) def test_updated_limit_applies_when_started_without_changing_profile(self): with tempfile.TemporaryDirectory() as root: units=MemoryUnits();manager=self.manager(root,units) value=helpers.NativeRuntimeManagerTests().payload(stopped=True);result=manager.create(value) generation={k:result[k] for k in ['runtime_id','binding_version','network_id']} manager.change_state(value['alias'],'start',generation,memory_limit_mb=4096) self.assertEqual(units.limits[manager._records()[0].browser_unit]['MemoryMax'],'4096M') record=manager._records()[0] self.assertEqual(record.profile_id,value['profile_id']) self.assertEqual(record.command,value['cmd']) before=units.start_count current=manager._public(manager._records()[0], ready=True) generation={k:current[k] for k in ['runtime_id','binding_version','network_id']} manager.change_state(value['alias'],'start',generation,memory_limit_mb=8192) self.assertEqual(units.start_count,before) self.assertEqual(manager._records()[0].memory_limit_mb,4096)