def test_service_started_lock_call(self, mock_threading): services = connect_services([FakeService(name='service1', dependencies=[]), FakeService(name='service2', dependencies=['service1'])]) context = RunningContext(services, DEFAULT_OPTIONS) context.service_started(services['service1']) mock_lock = mock_threading.Lock.return_value assert mock_lock.__enter__.call_count == 1
def test_start_new_if_always_start_new(self): service = FakeService() service.always_start_new = True options = Options(network=Network(name='the-network', id='the-network-id'), timeout=1, remove=True, run_dir='/etc', build=[]) agent = ServiceAgent(service, options, None) restarted = False def start(): nonlocal restarted restarted = True self.docker._existing_containers = [ Bunch(status='exited', start=start, network='the-network', attrs={'Config': { 'Env': [] }}, name="{}-testing-123".format(service.name)) ] agent.run_image() assert len(self.docker._services_started) == 1 assert not restarted
def test_fail_dependencies(self): """If a service fails to start, all the other services that depend on it are also registered as failed""" services = connect_services([FakeService(name='service1', dependencies=[]), FakeService(name='service2', dependencies=['service1'])]) context = RunningContext(services, DEFAULT_OPTIONS) context.service_failed(services['service1']) assert len(context.failed_services) == 2
def test_ready_to_start_and_stop(self): services = connect_services([FakeService(name='service1', dependencies=[]), FakeService(name='service2', dependencies=['service1'])]) context = RunningContext(services, DEFAULT_OPTIONS) assert len(context.ready_to_start) == 1 assert context.ready_to_start[0].service == services['service1'] assert len(context.ready_to_stop) == 1 assert context.ready_to_stop[0].service == services['service2']
def test_done_on_fail(self): services = connect_services([FakeService(name='service1', dependencies=[]), FakeService(name='service2', dependencies=[])]) context = RunningContext(services, DEFAULT_OPTIONS) assert not context.done context.service_started(services['service1']) assert not context.done context.service_failed(services['service2']) assert context.done
def test_service_failed_lock_call(self, mock_threading): services = connect_services([FakeService(name='service1', dependencies=[]), FakeService(name='service2', dependencies=['service1'])]) context = RunningContext(services, DEFAULT_OPTIONS) context.service_failed(services['service1']) mock_lock = mock_threading.Lock.return_value # This has to be 2 because service1 has a dependency, and it has to be # locked as well assert mock_lock.__enter__.call_count == 2
def test_if_build_from_and_latest(self): fake_context = FakeRunningContext() fake_service = FakeService() fake_service.image = "service:latest" fake_service.build_from = "the/service/dir" agent = ServiceAgent(fake_service, DEFAULT_OPTIONS, fake_context) agent.start_service() agent.join() assert len(self.docker._images_built) == 1
def test_build_on_start(self): fake_context = FakeRunningContext() fake_service = FakeService() fake_service.build_from = "the/service/dir" options = attr.evolve(DEFAULT_OPTIONS, build=[fake_service.name]) agent = ServiceAgent(fake_service, options, fake_context) agent.start_service() agent.join() assert len(self.docker._images_built) == 1
def test_build_image_dockerfile(self): fake_service = FakeService(name='myservice') fake_service.dockerfile = 'Dockerfile.other' fake_service.build_from = "the/service/dir" agent = ServiceAgent(fake_service, DEFAULT_OPTIONS, FakeRunningContext()) agent.build_image() assert len(self.docker._images_built) == 1 _, dockerfile, _ = self.docker._images_built[0] assert dockerfile == 'Dockerfile.other'
def test_service_stopped(self): services = connect_services([FakeService(name='service1', dependencies=[]), FakeService(name='service2', dependencies=['service1'])]) context = RunningContext(services, DEFAULT_OPTIONS) context.service_stopped(services['service2']) assert len(context.agent_set) == 1 assert len(context.processed_services) == 1 assert context.processed_services[0] is services['service2'] assert services['service1'] in context.agent_set assert context.agent_set[services['service1']].can_stop
def test_run_image_extrapolate_env(self): service = FakeService() service.env = {'ENV_ONE': 'http://{host}:{port:d}'} context.Context['host'] = 'zombo.com' context.Context['port'] = 80 agent = ServiceAgent(service, DEFAULT_OPTIONS, None) agent.run_image() assert len(self.docker._services_started) == 1 _, service, _ = self.docker._services_started[0] assert service.env['ENV_ONE'] == 'http://zombo.com:80'
def test_build_image(self, mock_datetime): now = datetime.now() mock_datetime.now.return_value = now fake_service = FakeService(name='myservice') fake_service.build_from = "the/service/dir" agent = ServiceAgent(fake_service, DEFAULT_OPTIONS, FakeRunningContext()) retval = agent.build_image() assert len(self.docker._images_built) == 1 build_dir, dockerfile, image_tag = self.docker._images_built[0] assert build_dir == "/etc/the/service/dir" assert dockerfile == 'Dockerfile' assert image_tag == now.strftime("myservice-%Y-%m-%d-%H%M") assert retval == image_tag assert RunCondition.BUILD_IMAGE in agent.run_condition.actions
def test_stop_container_does_not_exist(self): fake_context = FakeRunningContext() fake_service = FakeService(exception_at_init=ValueError) agent = ServiceAgent(fake_service, DEFAULT_OPTIONS, fake_context) agent.stop_service() agent.join() assert agent.status == AgentStatus.STOPPED
def test_service_failed(self): service = FakeService(name='service1', dependencies=[]) context = RunningContext({'service': service}, DEFAULT_OPTIONS) context.service_failed(service) assert len(context.failed_services) == 1 assert len(context.agent_set) == 0 assert len(context.processed_services) == 0
def test_start_existing_if_differing_env_value_type_but_not_string(self): service = FakeService() service.env = {'KEY': 12345} agent = ServiceAgent(service, DEFAULT_OPTIONS, None) self.docker._existing_containers = [ Bunch(status='exited', network='the-network', id='longass-container-id', image=Bunch(tags=[service.image]), attrs={'Config': { 'Env': ['KEY=12345'] }}, name="{}-testing-123".format(service.name)) ] agent.run_image() assert len(self.docker._services_started) == 0
def test_pre_start_before_run(self): fake_context = FakeRunningContext() fake_service = FakeService() assert not fake_service.pre_start_called agent = ServiceAgent(fake_service, DEFAULT_OPTIONS, fake_context) agent.start_service() agent.join() assert fake_service.pre_start_called
def test_run_image(self): agent = ServiceAgent(FakeService(), DEFAULT_OPTIONS, None) agent.run_image() assert len(self.docker._services_started) == 1 prefix, service, network = self.docker._services_started[0] assert prefix == "service1-testing" assert service.name == 'service1' assert service.image == 'not/used' assert network.name == 'the-network'
def test_ping_and_init_after_run(self): fake_context = FakeRunningContext() fake_service = FakeService() agent = ServiceAgent(fake_service, DEFAULT_OPTIONS, fake_context) agent.start_service() agent.join() assert len(fake_context.started_services) == 1 assert fake_context.started_services[0].name == 'service1' assert fake_service.ping_count == 1 assert fake_service.init_called
def test_call_collection_failed_on_error(self): fake_context = FakeRunningContext() fake_service = FakeService(exception_at_init=ValueError) agent = ServiceAgent(fake_service, DEFAULT_OPTIONS, fake_context) agent.start_service() agent.join() assert fake_service.ping_count > 0 assert fake_context.started_services == [] assert len(fake_context.failed_services) == 1 assert fake_context.failed_services[0].name == 'service1'
def test_repeat_ping_and_timeout(self, mock_time): mock_time.monotonic.side_effect = [0, 0.2, 0.6, 0.8, 1] fake_context = FakeRunningContext() fake_service = FakeService(fail_ping=True) agent = ServiceAgent(fake_service, DEFAULT_OPTIONS, fake_context) agent.start_service() agent.join() assert fake_service.ping_count == 3 assert mock_time.sleep.call_count == 3 assert agent.status == AgentStatus.FAILED assert len(fake_context.failed_services) == 1 assert fake_context.failed_services[0] is fake_service
def test_agent_status_change_happy_path(self): class ServiceAgentTestSubclass(ServiceAgent): def ping(self): assert self.status == 'in-progress' return super().ping() agent = ServiceAgentTestSubclass(FakeService(), DEFAULT_OPTIONS, FakeRunningContext()) assert agent.status == 'null' agent.start_service() agent.join() assert agent.status == 'started'
def test_agent_status_change_sad_path(self): class ServiceAgentTestSubclass(ServiceAgent): def ping(self): assert self.status == 'in-progress' raise ValueError("I failed miserably") agent = ServiceAgentTestSubclass(FakeService(), DEFAULT_OPTIONS, FakeRunningContext()) assert agent.status == 'null' agent.start_service() agent.join() assert agent.status == 'failed'
def test_start_new_container_if_differing_env_value(self): service = FakeService() service.env = {'KEY': 'some-value'} agent = ServiceAgent(service, DEFAULT_OPTIONS, None) self.docker._existing_containers = [ Bunch(status='exited', network='the-network', id='longass-container-id', image=Bunch(tags=[service.image]), attrs={'Config': { 'Env': ['KEY=other-value'] }}, name="{}-miniboss-123".format(service.name)) ] agent.run_image() assert len(self.docker._services_started) == 1 prefix, service, network = self.docker._services_started[0] assert prefix == "service1-testing" assert service.name == 'service1' assert service.image == 'not/used' assert network.name == 'the-network' assert self.docker._containers_ran == []
def test_skip_if_running_on_same_network(self): service = FakeService() agent = ServiceAgent(service, DEFAULT_OPTIONS, None) self.docker._existing_containers = [ Bunch(status='running', name="{}-testing-123".format(service.name), network='the-network') ] agent.run_image() assert len(self.docker._services_started) == 0 assert len(self.docker._existing_queried) == 1 assert self.docker._existing_queried[0] == ("service1-testing", Network( name="the-network", id="the-network-id"))
def test_stop_existing_container(self): fake_context = FakeRunningContext() fake_service = FakeService(exception_at_init=ValueError) container = FakeContainer(name='{}-testing-5678'.format( fake_service.name), network='the-network', status='running') self.docker._existing_containers = [container] agent = ServiceAgent(fake_service, DEFAULT_OPTIONS, fake_context) agent.stop_service() agent.join() assert agent.status == AgentStatus.STOPPED assert container.stopped assert len(fake_context.stopped_services) == 1 assert fake_context.stopped_services[0] is fake_service
def test_start_old_container_if_exists(self): service = FakeService() agent = ServiceAgent(service, DEFAULT_OPTIONS, None) self.docker._existing_containers = [ Bunch(status='exited', network='the-network', id='longass-container-id', image=Bunch(tags=[service.image]), attrs={'Config': { 'Env': [] }}, name="{}-testing-123".format(service.name)) ] agent.run_image() assert len(self.docker._services_started) == 0 assert self.docker._containers_ran == ['longass-container-id']
def test_service_failed_on_failed_ping(self): fake_context = FakeRunningContext() fake_service = FakeService(fail_ping=True) # Using options with low timeout so that test doesn't hang options = Options(network=Network(name='the-network', id='the-network-id'), timeout=0.1, remove=True, run_dir='/etc', build=[]) agent = ServiceAgent(fake_service, options, fake_context) agent.start_service() agent.join() assert fake_service.ping_count > 0 assert fake_context.started_services == [] assert len(fake_context.failed_services) == 1 assert fake_context.failed_services[0].name == 'service1'
def test_yes_ping_no_init_if_started(self): service = FakeService() fake_context = FakeRunningContext() agent = ServiceAgent(service, DEFAULT_OPTIONS, fake_context) self.docker._existing_containers = [ Bunch(status='exited', network='the-network', id='longass-container-id', image=Bunch(tags=[service.image]), attrs={'Config': { 'Env': [] }}, name="{}-testing-123".format(service.name)) ] agent.start_service() agent.join() assert service.ping_count == 1 assert not service.init_called assert self.docker._containers_ran == ['longass-container-id']
def test_no_pre_ping_or_init_if_running(self): service = FakeService() fake_context = FakeRunningContext() options = Options(network=Network(name='the-network', id='the-network-id'), timeout=1, remove=True, run_dir='/etc', build=[]) agent = ServiceAgent(service, options, fake_context) self.docker._existing_containers = [ Bunch(status='running', network='the-network', name="{}-testing-123".format(service.name)) ] agent.start_service() agent.join() assert service.ping_count == 0 assert not service.init_called assert not service.pre_start_called