Пример #1
0
    def test_evaluation_of_queue_settings(self):
        settings = Settings(queue=LIFO())

        simulation = Simulation(InMemoryDataStorage(None))
        simulation.evaluate(settings)

        task_pool = simulation.environment.look_up(Symbols.QUEUE).delegate.delegate.delegate
        self.assertIsInstance(task_pool, LIFOTaskPool)
Пример #2
0
class ServiceTests(TestCase):
    """
    Factor out the creation of the simulation, as well as a few helpers needed to create services that do
    reject requests, or services that always fail, etc.
    """
    def setUp(self):
        self.simulation = Simulation(InMemoryDataStorage(None))

    def define(self, symbol, value):
        self.simulation.environment.define(symbol, value)
        return value

    def look_up(self, symbol):
        return self.simulation.environment.look_up(symbol)

    def evaluate(self, expression, continuation=lambda x: x):
        return self.simulation.evaluate(expression, continuation)

    def simulate_until(self, end):
        self.simulation.run_until(end)

    def query(self,
              service_name,
              operation,
              on_success=lambda: None,
              on_error=lambda: None):
        request = Query(self.a_running_task(), operation, 1, lambda s: None)
        request.on_success = on_success
        request.on_error = on_error
        self.send(request, service_name)
        return request

    def a_running_task(self):
        task = Task(self.fake_client())
        task.status = TaskStatus.BLOCKED  # A regular evaluation would block it after sending the request
        return task

    def trigger(self,
                service_name,
                operation,
                on_success=lambda: None,
                on_error=lambda: None):
        request = Trigger(self.a_running_task(), operation, 1, lambda s: None)
        request.on_success = on_success
        request.on_error = on_error
        self.send(request, service_name)
        return request

    def send(self, request, service_name):
        service_name = self.look_up(service_name)
        request.send_to(service_name)

    def fake_client(self):
        fake_client = MagicMock()
        fake_client.schedule = self.simulation.schedule
        fake_client.next_request_id = MagicMock(
            side_effect=list(range(1, 1000)))
        return fake_client
Пример #3
0
    def test_evaluation_of_queue_settings(self):
        settings = Settings(queue=LIFO())

        simulation = Simulation(InMemoryDataStorage(None))
        simulation.evaluate(settings)

        task_pool = simulation.environment.look_up(
            Symbols.QUEUE).delegate.delegate.delegate
        self.assertIsInstance(task_pool, LIFOTaskPool)
Пример #4
0
    def test_evaluation_of_autoscaling_settings(self):
        PERIOD = 23
        settings = Settings(autoscaling=Autoscaling(PERIOD, limits=(3, 5)))

        simulation = Simulation(InMemoryDataStorage(None))
        simulation.evaluate(settings)

        autoscaler = simulation.environment.look_up(Symbols.AUTOSCALING)

        self.assertIsInstance(autoscaler, AutoScaler)
        self.assertEqual(PERIOD, autoscaler.period)
        self.assertEqual((3, 5), autoscaler.limits)
Пример #5
0
    def test_evaluation_of_autoscaling_settings(self):
        PERIOD = 23
        settings = Settings(autoscaling=Autoscaling(PERIOD, limits=(3, 5)))

        simulation = Simulation(InMemoryDataStorage(None))
        simulation.evaluate(settings)

        autoscaler = simulation.environment.look_up(Symbols.AUTOSCALING)

        self.assertIsInstance(autoscaler, AutoScaler)
        self.assertEqual(PERIOD, autoscaler.period)
        self.assertEqual((3, 5), autoscaler.limits)
Пример #6
0
class ServiceTests(TestCase):
    """
    Factor out the creation of the simulation, as well as a few helpers needed to create services that do
    reject requests, or services that always fail, etc.
    """

    def setUp(self):
        self.simulation = Simulation(InMemoryDataStorage(None))

    def define(self, symbol, value):
        self.simulation.environment.define(symbol, value)
        return value

    def look_up(self, symbol):
        return self.simulation.environment.look_up(symbol)

    def evaluate(self, expression, continuation=lambda x:x):
        return self.simulation.evaluate(expression, continuation)

    def simulate_until(self, end):
        self.simulation.run_until(end)

    def query(self, service_name, operation, on_success=lambda:None, on_error=lambda:None):
        request = Query(self.a_running_task(), operation, 1, lambda s:None)
        request.on_success = on_success
        request.on_error = on_error
        self.send(request, service_name)
        return request

    def a_running_task(self):
        task = Task(self.fake_client())
        task.status = TaskStatus.BLOCKED # A regular evaluation would block it after sending the request
        return task

    def trigger(self, service_name, operation, on_success=lambda:None, on_error=lambda:None):
        request = Trigger(self.a_running_task(), operation, 1, lambda s:None)
        request.on_success = on_success
        request.on_error = on_error
        self.send(request, service_name)
        return request

    def send(self, request, service_name):
        service_name = self.look_up(service_name)
        request.send_to(service_name)

    def fake_client(self):
        fake_client = MagicMock()
        fake_client.schedule = self.simulation.schedule
        fake_client.next_request_id = MagicMock(side_effect=range(1, 1000))
        return fake_client
Пример #7
0
 def setUp(self):
     self.simulation = Simulation(InMemoryDataStorage(None))
Пример #8
0
class TestInterpreter(TestCase):
    def setUp(self):
        self.simulation = Simulation(InMemoryDataStorage(None))

    def define(self, symbol, value):
        self.simulation.environment.define(symbol, value)
        return value

    def look_up(self, symbol):
        return self.simulation.environment.look_up(symbol)

    def evaluate(self, expression, continuation=lambda x: x):
        return self.simulation.evaluate(expression, continuation)

    def verify_definition(self, symbol, kind):
        value = self.look_up(symbol)
        self.assertTrue(isinstance(value, kind))

    def send_request(self,
                     service_name,
                     operation_name,
                     on_success=lambda: None,
                     on_error=lambda: None):
        service = self.look_up(service_name)
        request = self.fake_request(operation_name,
                                    on_success=on_success,
                                    on_error=on_error)
        request.send_to(service)
        return request

    def simulate_until(self, end):
        self.simulation.run_until(end)

    def test_evaluate_blocking_service_invocation(self):
        db = self.define("DB", self.fake_service())
        self.evaluate(
            DefineService("Front-end",
                          DefineOperation("checkout", Query("DB", "op"))))

        self.send_request("Front-end", "checkout")
        self.simulate_until(10)

        self.assertEqual(db.process.call_count, 1)

    def test_trigger_rejection(self):
        db = self.define("DB", self._a_service_that_rejects_requests())
        front_end = self.evaluate(
            DefineService("Front-end",
                          DefineOperation("checkout", Trigger("DB",
                                                              "op")))).value

        request = self.send_request("Front-end", "checkout")

        from mad.simulation.monitoring import Statistics
        with patch.object(Statistics, "reset"):
            self.simulate_until(10)

            self.assertTrue(request.status == RequestStatus.ERROR)
            monitor = front_end.look_up(Symbols.MONITOR)
            self.assertEqual(0., monitor._reliability())

    def test_query_make_services_busy(self):
        db = self.evaluate(
            DefineService("DB", DefineOperation("Select", Think(2)))).value
        front_end = self.evaluate(
            DefineService("Front-end",
                          DefineOperation("show", Query("DB",
                                                        "Select")))).value

        request = self.send_request("Front-end", "show")
        self.simulate_until(1)
        self.assertEqual(
            100.0,
            front_end.workers.utilisation)  # The front-end should be busy

        self.simulate_until(2)
        self.assertEqual(
            0.0,
            front_end.workers.utilisation)  # The front-end should be released
        self.assertEqual(
            0.0, db.workers.utilisation)  # DB has not yet received the request

        self.simulate_until(3)
        self.assertEqual(
            0.0,
            front_end.workers.utilisation)  # The front-end should be released
        self.assertEqual(100.0, db.workers.utilisation)  # DB busy thinking

        self.simulate_until(5)
        self.assertEqual(
            0.0, front_end.workers.utilisation)  # Front end has nothing to do
        self.assertEqual(100.0,
                         db.workers.utilisation)  # DB busy sending answer

        self.simulate_until(6)
        self.assertEqual(
            0.0, front_end.workers.utilisation)  # Front end has nothing to do
        self.assertEqual(
            0.0, db.workers.utilisation)  # DB has nothing to do anymore

        self.simulate_until(7)
        self.assertEqual(
            100.0, front_end.workers.utilisation)  # Front end busy replying
        self.assertEqual(
            0.0, db.workers.utilisation)  # DB has nothing to do anymore

        self.simulate_until(8)
        self.assertEqual(
            0.0, front_end.workers.utilisation)  # Front end busy replying
        self.assertEqual(
            0.0, db.workers.utilisation)  # DB has nothing to do anymore

        self.simulate_until(9)
        self.assertTrue(request.status == RequestStatus.OK)

    def test_trigger_make_services_busy(self):
        db = self.evaluate(
            DefineService("DB", DefineOperation("Select", Think(2)))).value
        front_end = self.evaluate(
            DefineService("Front-end",
                          DefineOperation("show", Trigger("DB",
                                                          "Select")))).value

        request = self.send_request("Front-end", "show")
        self.simulate_until(1)
        self.assertEqual(
            100.0,
            front_end.workers.utilisation)  # The front-end should be busy
        self.assertEqual(0.0, db.workers.utilisation)  # DB has nothing to do

        self.simulate_until(2)
        self.assertEqual(
            0.0,
            front_end.workers.utilisation)  # The front-end should be released
        self.assertEqual(
            0.0, db.workers.utilisation)  # DB has not yet received the request

        self.simulate_until(3)
        self.assertEqual(
            0.0,
            front_end.workers.utilisation)  # The front-end should be released
        self.assertEqual(100.0, db.workers.utilisation)  # DB busy thinking

        self.simulate_until(4)
        self.assertEqual(
            100.0, front_end.workers.utilisation
        )  # Front end has received the acceptance ack and is replying
        self.assertEqual(100.0,
                         db.workers.utilisation)  # DB busy sending answer

        self.simulate_until(5)
        self.assertEqual(
            0.0, front_end.workers.utilisation)  # Front end has nothing to do
        self.assertEqual(
            0.0, db.workers.utilisation)  # DB has nothing to do anymore

        self.simulate_until(6)
        self.assertTrue(request.status == RequestStatus.OK)

    def test_rejected_query_make_services_busy(self):
        db = self._a_service_that_rejects_requests()
        self.define("DB", db)
        front_end = self.evaluate(
            DefineService("Front-end",
                          DefineOperation("show", Query("DB",
                                                        "Select")))).value

        request = self.send_request("Front-end", "show")

        self.simulate_until(1)
        self.assertEqual(
            100.0,
            front_end.workers.utilisation)  # The front-end should be busy

        self.simulate_until(2)
        self.assertEqual(
            0.0,
            front_end.workers.utilisation)  # The front-end should be released

        self.simulate_until(3)
        self.assertEqual(
            0.0,
            front_end.workers.utilisation)  # The front-end should be released

        self.simulate_until(4)
        self.assertEqual(
            100.0, front_end.workers.utilisation
        )  # Front end has received the acceptance ack and is replying

        self.simulate_until(5)
        self.assertEqual(
            0.0, front_end.workers.utilisation)  # Front end has nothing to do

        self.simulate_until(6)
        self.assertTrue(request.status == RequestStatus.ERROR)

    def test_failed_query_make_services_busy(self):
        db = self._a_service_that_accepts_but_fails(after=3)
        self.define("DB", db)
        front_end = self.evaluate(
            DefineService("Front-end",
                          DefineOperation("show", Query("DB",
                                                        "Select")))).value

        request = self.send_request("Front-end", "show")

        self.simulate_until(1)
        self.assertEqual(
            100.0,
            front_end.workers.utilisation)  # The front-end should be busy

        self.simulate_until(2)
        self.assertEqual(
            0.0,
            front_end.workers.utilisation)  # The front-end should be released

        self.simulate_until(3)
        self.assertEqual(
            0.0,
            front_end.workers.utilisation)  # The front-end should be released

        self.simulate_until(7)
        self.assertEqual(
            100.0,
            front_end.workers.utilisation)  # Front-end forward the error

        self.simulate_until(8)
        self.assertEqual(
            0.0,
            front_end.workers.utilisation)  # The front-end should be released

        self.simulate_until(9)
        self.assertTrue(request.status == RequestStatus.ERROR)

    def test_rejected_trigger_make_services_busy(self):
        db = self._a_service_that_rejects_requests()
        self.define("DB", db)
        front_end = self.evaluate(
            DefineService("Front-end",
                          DefineOperation("show", Trigger("DB",
                                                          "Select")))).value

        request = self.send_request("Front-end", "show")

        self.simulate_until(1)
        self.assertEqual(
            100.0,
            front_end.workers.utilisation)  # The front-end should be busy

        self.simulate_until(2)
        self.assertEqual(
            0.0,
            front_end.workers.utilisation)  # The front-end should be released

        self.simulate_until(3)
        self.assertEqual(
            0.0,
            front_end.workers.utilisation)  # The front-end should be released

        self.simulate_until(4)
        self.assertEqual(
            100.0, front_end.workers.utilisation
        )  # Front end has received the acceptance ack and is replying

        self.simulate_until(5)
        self.assertEqual(
            0.0, front_end.workers.utilisation)  # Front end has nothing to do

        self.simulate_until(6)
        self.assertTrue(request.status == RequestStatus.ERROR)

    def test_evaluate_timeout_queries(self):
        db = self.evaluate(DefineService("DB",
                                         DefineOperation("op",
                                                         Think(8)))).value
        front_end = self.evaluate(
            DefineService(
                "Front-end",
                DefineOperation("checkout", Query("DB", "op",
                                                  timeout=5)))).value

        request = self.send_request("Front-end", "checkout")
        self.simulate_until(8)
        self.assertTrue(request.status == RequestStatus.ERROR)

        self.simulate_until(12)
        self.assertEqual(RequestStatus.ERROR, request.status)
        self.assertEqual(
            0, len(front_end.tasks.delegate.delegate.delegate.paused))
        self.assertEqual(0, front_end.tasks.blocked_count)
        self.assertTrue(front_end.workers.are_available)
        self.assertEqual(0, db.tasks.blocked_count)
        self.assertEqual(0, len(db.tasks.delegate.delegate.delegate.paused))
        self.assertTrue(db.workers.are_available)

    def test_evaluate_timeout_on_query(self):
        """
        Test that workers are released when a task is resumed, but its associated request has been discarded
        """
        db = self.evaluate(
            DefineService("DB", DefineOperation("insert", Think(8)))).value
        storage = self.evaluate(
            DefineService("Storage",
                          DefineOperation("store", Query("DB",
                                                         "insert")))).value
        notifier = self.evaluate(
            DefineService(
                "Notifier",
                DefineOperation("notify", Query("Storage", "store",
                                                timeout=5)))).value

        request = self.send_request("Notifier", "notify")
        self.simulate_until(8)
        self.assertTrue(request.status == RequestStatus.ERROR)

        self.simulate_until(50)  # Should have been release by then
        self.assertTrue(storage.workers.are_available)
        self.assertEqual(0,
                         len(storage.tasks.delegate.delegate.delegate.paused))

    def test_evaluate_timeout_no_expiration(self):
        db = self.evaluate(DefineService("DB",
                                         DefineOperation("op",
                                                         Think(1)))).value
        front_end = self.evaluate(
            DefineService(
                "Front-end",
                DefineOperation(
                    "checkout",
                    Retry(expression=Query("DB", "op", timeout=1),
                          delay=Delay(2, "constant"),
                          limit=5)))).value

        request = self.send_request("Front-end", "checkout")
        self.simulate_until(25)

        self.assertEqual(RequestStatus.ERROR, request.status)

    def test_sequence_evaluation(self):
        db = self.define("DB", self._a_service_that_accepts_but_fails(after=2))
        self.evaluate(
            DefineService(
                "Front-end",
                DefineOperation(
                    "checkout",
                    Sequence(Trigger("DB", "op"), Trigger("DB", "op")))))

        self.send_request("Front-end", "checkout")
        self.simulate_until(20)

        self.assertEqual(db.process.call_count, 2)

    def test_operation_invocation(self):
        # TODO: Check whether this test is still useful
        db = self.define("DB", self.service_that_always_fails())
        self.evaluate(
            DefineService("Front-end",
                          DefineOperation("checkout", Trigger("DB", "op"))))

        self.send_request("Front-end", "checkout")
        self.simulate_until(20)

        self.assertEqual(db.process.call_count, 1)

    def test_thinking(self):
        db = self.define("DB", self.service_that_always_fails())
        self.evaluate(
            DefineService(
                "Front-end",
                DefineOperation("checkout",
                                Sequence(Think(5), Trigger("DB", "op")))))

        self.send_request("Front-end", "checkout")

        self.assertEqual(db.process.call_count, 0)
        self.simulate_until(10)
        self.assertEqual(db.process.call_count, 1)

    def test_retry_and_succeed(self):
        db = self.define("DB", self.service_that_succeeds_at_attempt(2))
        self.evaluate(
            DefineService(
                "Front-end",
                DefineOperation(
                    "checkout",
                    Retry(Query("DB", "insert"),
                          limit=5,
                          delay=Delay(10, "constant")))))

        def test_fail():
            self.fail("Expected failed request")

        self.send_request("Front-end", "checkout", on_error=test_fail)
        self.simulate_until(200)

        self.assertEqual(db.process.call_count, 2)

    def test_retry_and_fail(self):
        db = self.define("DB", self.service_that_succeeds_at_attempt(15))
        self.evaluate(
            DefineService(
                "Front-end",
                DefineOperation(
                    "checkout",
                    Retry(Query("DB", "insert"),
                          limit=5,
                          delay=Delay(10, "constant")))))

        def test_fail():
            self.fail("Expected successful request")

        self.send_request("Front-end", "checkout", on_success=test_fail)
        self.simulate_until(200)

        self.assertEqual(db.process.call_count, 5)

    def test_fail(self):
        self.evaluate(DefineService("DB", DefineOperation("Select", Fail())))

        def test_failed():
            self.fail("Expected successful request")

        self.send_request("DB", "Select", on_success=test_failed)
        self.simulate_until(20)

    def test_ignore_error(self):
        db1 = self.define("DB1", self.service_that_always_fails())
        db2 = self.define("DB2", self.fake_service())
        self.evaluate(
            DefineService(
                "Front-end",
                DefineOperation(
                    "checkout",
                    Sequence(IgnoreError(Query("DB1", "op")),
                             Trigger("DB2", "op")))))

        self.send_request("Front-end", "checkout")
        self.simulate_until(20)

        self.assertEqual(db1.process.call_count, 1)
        self.assertEqual(db2.process.call_count, 1)

    def test_operation_definition(self):
        self.evaluate(DefineOperation("op", Trigger("serviceX", "op")))

        self.verify_definition("op", Operation)

    def test_service_request(self):
        fake_service = self.define("serviceX", self.fake_service())
        service = self.evaluate(
            DefineService("my-service",
                          DefineOperation("op", Trigger("serviceX",
                                                        "op")))).value

        request = self.fake_request("op")
        request.send_to(service)
        self.simulate_until(10)

        self.assertEqual(fake_service.process.call_count, 1)

    def test_service_definition(self):
        fake_service = self.define("service Y", self.fake_service())
        self.evaluate(
            DefineService("Service X",
                          DefineOperation("op", Trigger("service Y", "foo"))))

        self.verify_definition("Service X", Service)
        service = self.look_up("Service X")

        request = self.fake_request("op")
        request.send_to(service)
        self.simulate_until(10)

        self.assertEqual(fake_service.process.call_count, 1)

    def test_client_stub_definition(self):
        client = self.evaluate(
            Sequence(
                DefineService("Service X", DefineOperation("op", Think(2))),
                DefineClientStub("Client", 10, Query("Service X",
                                                     "op")))).value
        client.on_success = MagicMock()

        self.simulate_until(26)

        monitor = client.look_up(Symbols.MONITOR)
        self.assertEqual(monitor.tasks.successful, 2)

    def fake_request(self,
                     operation,
                     on_success=lambda: None,
                     on_error=lambda: None):
        request = SQuery(Task(self.fake_client()), operation, 1,
                         lambda s: None)
        request.on_error = on_error
        request.on_success = on_success
        return request

    def fake_service(self, name="DB"):
        fake_service = MagicMock()
        fake_service.name = name
        fake_service.process = MagicMock()
        fake_service.schedule = self.simulation.schedule
        return fake_service

    def fake_client(self):
        fake_client = MagicMock()
        fake_client.schedule = self.simulation.schedule
        fake_client.next_request_id = MagicMock(side_effect=range(1, 100))
        return fake_client

    def _a_service_that_rejects_requests(self):
        def always_reject(request):
            request.reject()

        service = self.fake_service()
        service.process.side_effect = always_reject
        return service

    def _a_service_that_accepts_but_fails(self, after=4):
        def always_accept(request):
            def do_fail():
                request.reply_error()

            request.accept()
            self.simulation._scheduler.after(after, do_fail)

        service = self.fake_service()
        service.process.side_effect = always_accept
        return service

    def _a_service_that_replies_after(self, after=4):
        def always_accept(request):
            def do_succeed():
                request.reply_success()

            request.accept()
            self.simulation._scheduler.after(after, do_succeed)

        service = self.fake_service()
        service.process.side_effect = always_accept
        return service

    def service_that_always_fails(self):
        def always_fail(request):
            request.reply_error()

        service = self.fake_service()
        service.process.side_effect = always_fail
        return service

    def service_that_succeeds_at_attempt(self, successful_attempt):
        attempt = 0

        def respond(request):
            nonlocal attempt
            attempt += 1
            if attempt == successful_attempt:
                request.reply_success()
            else:
                request.reply_error()

        service = self.fake_service()
        service.process.side_effect = respond
        service.schedule = self.simulation.schedule
        return service
Пример #9
0
 def evaluate(self, expression):
     simulation = Simulation(InMemoryDataStorage(None))
     simulation.evaluate(expression)
     return simulation
Пример #10
0
Файл: ui.py Проект: fchauvel/MAD
 def _simulate(self, expression, arguments):
     simulation = Simulation(self.storage)
     simulation.evaluate(expression)
     simulation.run_until(arguments._time_limit, self.display)
     self.display.simulation_complete(arguments)
     return simulation
Пример #11
0
 def setUp(self):
     self.simulation = Simulation(InMemoryDataStorage(None))
Пример #12
0
class TestInterpreter(TestCase):
    def setUp(self):
        self.simulation = Simulation(InMemoryDataStorage(None))

    def define(self, symbol, value):
        self.simulation.environment.define(symbol, value)
        return value

    def look_up(self, symbol):
        return self.simulation.environment.look_up(symbol)

    def evaluate(self, expression, continuation=lambda x: x):
        return self.simulation.evaluate(expression, continuation)

    def verify_definition(self, symbol, kind):
        value = self.look_up(symbol)
        self.assertTrue(isinstance(value, kind))

    def send_request(self, service_name, operation_name, on_success=lambda: None, on_error=lambda: None):
        service = self.look_up(service_name)
        request = self.fake_request(operation_name, on_success=on_success, on_error=on_error)
        request.send_to(service)
        return request

    def simulate_until(self, end):
        self.simulation.run_until(end)

    def test_evaluate_blocking_service_invocation(self):
        db = self.define("DB", self.fake_service())
        self.evaluate(DefineService("Front-end", DefineOperation("checkout", Query("DB", "op"))))

        self.send_request("Front-end", "checkout")
        self.simulate_until(10)

        self.assertEqual(db.process.call_count, 1)

    def test_trigger_rejection(self):
        db = self.define("DB", self._a_service_that_rejects_requests())
        front_end = self.evaluate(DefineService("Front-end", DefineOperation("checkout", Trigger("DB", "op")))).value

        request = self.send_request("Front-end", "checkout")

        from mad.simulation.monitoring import Statistics

        with patch.object(Statistics, "reset"):
            self.simulate_until(10)

            self.assertTrue(request.status == RequestStatus.ERROR)
            monitor = front_end.look_up(Symbols.MONITOR)
            self.assertEqual(0.0, monitor._reliability())

    def test_query_make_services_busy(self):
        db = self.evaluate(DefineService("DB", DefineOperation("Select", Think(2)))).value
        front_end = self.evaluate(DefineService("Front-end", DefineOperation("show", Query("DB", "Select")))).value

        request = self.send_request("Front-end", "show")
        self.simulate_until(1)
        self.assertEqual(100.0, front_end.workers.utilisation)  # The front-end should be busy

        self.simulate_until(2)
        self.assertEqual(0.0, front_end.workers.utilisation)  # The front-end should be released
        self.assertEqual(0.0, db.workers.utilisation)  # DB has not yet received the request

        self.simulate_until(3)
        self.assertEqual(0.0, front_end.workers.utilisation)  # The front-end should be released
        self.assertEqual(100.0, db.workers.utilisation)  # DB busy thinking

        self.simulate_until(5)
        self.assertEqual(0.0, front_end.workers.utilisation)  # Front end has nothing to do
        self.assertEqual(100.0, db.workers.utilisation)  # DB busy sending answer

        self.simulate_until(6)
        self.assertEqual(0.0, front_end.workers.utilisation)  # Front end has nothing to do
        self.assertEqual(0.0, db.workers.utilisation)  # DB has nothing to do anymore

        self.simulate_until(7)
        self.assertEqual(100.0, front_end.workers.utilisation)  # Front end busy replying
        self.assertEqual(0.0, db.workers.utilisation)  # DB has nothing to do anymore

        self.simulate_until(8)
        self.assertEqual(0.0, front_end.workers.utilisation)  # Front end busy replying
        self.assertEqual(0.0, db.workers.utilisation)  # DB has nothing to do anymore

        self.simulate_until(9)
        self.assertTrue(request.status == RequestStatus.OK)

    def test_trigger_make_services_busy(self):
        db = self.evaluate(DefineService("DB", DefineOperation("Select", Think(2)))).value
        front_end = self.evaluate(DefineService("Front-end", DefineOperation("show", Trigger("DB", "Select")))).value

        request = self.send_request("Front-end", "show")
        self.simulate_until(1)
        self.assertEqual(100.0, front_end.workers.utilisation)  # The front-end should be busy
        self.assertEqual(0.0, db.workers.utilisation)  # DB has nothing to do

        self.simulate_until(2)
        self.assertEqual(0.0, front_end.workers.utilisation)  # The front-end should be released
        self.assertEqual(0.0, db.workers.utilisation)  # DB has not yet received the request

        self.simulate_until(3)
        self.assertEqual(0.0, front_end.workers.utilisation)  # The front-end should be released
        self.assertEqual(100.0, db.workers.utilisation)  # DB busy thinking

        self.simulate_until(4)
        self.assertEqual(
            100.0, front_end.workers.utilisation
        )  # Front end has received the acceptance ack and is replying
        self.assertEqual(100.0, db.workers.utilisation)  # DB busy sending answer

        self.simulate_until(5)
        self.assertEqual(0.0, front_end.workers.utilisation)  # Front end has nothing to do
        self.assertEqual(0.0, db.workers.utilisation)  # DB has nothing to do anymore

        self.simulate_until(6)
        self.assertTrue(request.status == RequestStatus.OK)

    def test_rejected_query_make_services_busy(self):
        db = self._a_service_that_rejects_requests()
        self.define("DB", db)
        front_end = self.evaluate(DefineService("Front-end", DefineOperation("show", Query("DB", "Select")))).value

        request = self.send_request("Front-end", "show")

        self.simulate_until(1)
        self.assertEqual(100.0, front_end.workers.utilisation)  # The front-end should be busy

        self.simulate_until(2)
        self.assertEqual(0.0, front_end.workers.utilisation)  # The front-end should be released

        self.simulate_until(3)
        self.assertEqual(0.0, front_end.workers.utilisation)  # The front-end should be released

        self.simulate_until(4)
        self.assertEqual(
            100.0, front_end.workers.utilisation
        )  # Front end has received the acceptance ack and is replying

        self.simulate_until(5)
        self.assertEqual(0.0, front_end.workers.utilisation)  # Front end has nothing to do

        self.simulate_until(6)
        self.assertTrue(request.status == RequestStatus.ERROR)

    def test_failed_query_make_services_busy(self):
        db = self._a_service_that_accepts_but_fails(after=3)
        self.define("DB", db)
        front_end = self.evaluate(DefineService("Front-end", DefineOperation("show", Query("DB", "Select")))).value

        request = self.send_request("Front-end", "show")

        self.simulate_until(1)
        self.assertEqual(100.0, front_end.workers.utilisation)  # The front-end should be busy

        self.simulate_until(2)
        self.assertEqual(0.0, front_end.workers.utilisation)  # The front-end should be released

        self.simulate_until(3)
        self.assertEqual(0.0, front_end.workers.utilisation)  # The front-end should be released

        self.simulate_until(7)
        self.assertEqual(100.0, front_end.workers.utilisation)  # Front-end forward the error

        self.simulate_until(8)
        self.assertEqual(0.0, front_end.workers.utilisation)  # The front-end should be released

        self.simulate_until(9)
        self.assertTrue(request.status == RequestStatus.ERROR)

    def test_rejected_trigger_make_services_busy(self):
        db = self._a_service_that_rejects_requests()
        self.define("DB", db)
        front_end = self.evaluate(DefineService("Front-end", DefineOperation("show", Trigger("DB", "Select")))).value

        request = self.send_request("Front-end", "show")

        self.simulate_until(1)
        self.assertEqual(100.0, front_end.workers.utilisation)  # The front-end should be busy

        self.simulate_until(2)
        self.assertEqual(0.0, front_end.workers.utilisation)  # The front-end should be released

        self.simulate_until(3)
        self.assertEqual(0.0, front_end.workers.utilisation)  # The front-end should be released

        self.simulate_until(4)
        self.assertEqual(
            100.0, front_end.workers.utilisation
        )  # Front end has received the acceptance ack and is replying

        self.simulate_until(5)
        self.assertEqual(0.0, front_end.workers.utilisation)  # Front end has nothing to do

        self.simulate_until(6)
        self.assertTrue(request.status == RequestStatus.ERROR)

    def test_evaluate_timeout_queries(self):
        db = self.evaluate(DefineService("DB", DefineOperation("op", Think(8)))).value
        front_end = self.evaluate(
            DefineService("Front-end", DefineOperation("checkout", Query("DB", "op", timeout=5)))
        ).value

        request = self.send_request("Front-end", "checkout")
        self.simulate_until(8)
        self.assertTrue(request.status == RequestStatus.ERROR)

        self.simulate_until(12)
        self.assertEqual(RequestStatus.ERROR, request.status)
        self.assertEqual(0, len(front_end.tasks.delegate.delegate.delegate.paused))
        self.assertEqual(0, front_end.tasks.blocked_count)
        self.assertTrue(front_end.workers.are_available)
        self.assertEqual(0, db.tasks.blocked_count)
        self.assertEqual(0, len(db.tasks.delegate.delegate.delegate.paused))
        self.assertTrue(db.workers.are_available)

    def test_evaluate_timeout_on_query(self):
        """
        Test that workers are released when a task is resumed, but its associated request has been discarded
        """
        db = self.evaluate(DefineService("DB", DefineOperation("insert", Think(8)))).value
        storage = self.evaluate(DefineService("Storage", DefineOperation("store", Query("DB", "insert")))).value
        notifier = self.evaluate(
            DefineService("Notifier", DefineOperation("notify", Query("Storage", "store", timeout=5)))
        ).value

        request = self.send_request("Notifier", "notify")
        self.simulate_until(8)
        self.assertTrue(request.status == RequestStatus.ERROR)

        self.simulate_until(50)  # Should have been release by then
        self.assertTrue(storage.workers.are_available)
        self.assertEqual(0, len(storage.tasks.delegate.delegate.delegate.paused))

    def test_evaluate_timeout_no_expiration(self):
        db = self.evaluate(DefineService("DB", DefineOperation("op", Think(1)))).value
        front_end = self.evaluate(
            DefineService(
                "Front-end",
                DefineOperation(
                    "checkout", Retry(expression=Query("DB", "op", timeout=1), delay=Delay(2, "constant"), limit=5)
                ),
            )
        ).value

        request = self.send_request("Front-end", "checkout")
        self.simulate_until(25)

        self.assertEqual(RequestStatus.ERROR, request.status)

    def test_sequence_evaluation(self):
        db = self.define("DB", self._a_service_that_accepts_but_fails(after=2))
        self.evaluate(
            DefineService("Front-end", DefineOperation("checkout", Sequence(Trigger("DB", "op"), Trigger("DB", "op"))))
        )

        self.send_request("Front-end", "checkout")
        self.simulate_until(20)

        self.assertEqual(db.process.call_count, 2)

    def test_operation_invocation(self):
        # TODO: Check whether this test is still useful
        db = self.define("DB", self.service_that_always_fails())
        self.evaluate(DefineService("Front-end", DefineOperation("checkout", Trigger("DB", "op"))))

        self.send_request("Front-end", "checkout")
        self.simulate_until(20)

        self.assertEqual(db.process.call_count, 1)

    def test_thinking(self):
        db = self.define("DB", self.service_that_always_fails())
        self.evaluate(DefineService("Front-end", DefineOperation("checkout", Sequence(Think(5), Trigger("DB", "op")))))

        self.send_request("Front-end", "checkout")

        self.assertEqual(db.process.call_count, 0)
        self.simulate_until(10)
        self.assertEqual(db.process.call_count, 1)

    def test_retry_and_succeed(self):
        db = self.define("DB", self.service_that_succeeds_at_attempt(2))
        self.evaluate(
            DefineService(
                "Front-end",
                DefineOperation("checkout", Retry(Query("DB", "insert"), limit=5, delay=Delay(10, "constant"))),
            )
        )

        def test_fail():
            self.fail("Expected failed request")

        self.send_request("Front-end", "checkout", on_error=test_fail)
        self.simulate_until(200)

        self.assertEqual(db.process.call_count, 2)

    def test_retry_and_fail(self):
        db = self.define("DB", self.service_that_succeeds_at_attempt(15))
        self.evaluate(
            DefineService(
                "Front-end",
                DefineOperation("checkout", Retry(Query("DB", "insert"), limit=5, delay=Delay(10, "constant"))),
            )
        )

        def test_fail():
            self.fail("Expected successful request")

        self.send_request("Front-end", "checkout", on_success=test_fail)
        self.simulate_until(200)

        self.assertEqual(db.process.call_count, 5)

    def test_fail(self):
        self.evaluate(DefineService("DB", DefineOperation("Select", Fail())))

        def test_failed():
            self.fail("Expected successful request")

        self.send_request("DB", "Select", on_success=test_failed)
        self.simulate_until(20)

    def test_ignore_error(self):
        db1 = self.define("DB1", self.service_that_always_fails())
        db2 = self.define("DB2", self.fake_service())
        self.evaluate(
            DefineService(
                "Front-end",
                DefineOperation("checkout", Sequence(IgnoreError(Query("DB1", "op")), Trigger("DB2", "op"))),
            )
        )

        self.send_request("Front-end", "checkout")
        self.simulate_until(20)

        self.assertEqual(db1.process.call_count, 1)
        self.assertEqual(db2.process.call_count, 1)

    def test_operation_definition(self):
        self.evaluate(DefineOperation("op", Trigger("serviceX", "op")))

        self.verify_definition("op", Operation)

    def test_service_request(self):
        fake_service = self.define("serviceX", self.fake_service())
        service = self.evaluate(DefineService("my-service", DefineOperation("op", Trigger("serviceX", "op")))).value

        request = self.fake_request("op")
        request.send_to(service)
        self.simulate_until(10)

        self.assertEqual(fake_service.process.call_count, 1)

    def test_service_definition(self):
        fake_service = self.define("service Y", self.fake_service())
        self.evaluate(DefineService("Service X", DefineOperation("op", Trigger("service Y", "foo"))))

        self.verify_definition("Service X", Service)
        service = self.look_up("Service X")

        request = self.fake_request("op")
        request.send_to(service)
        self.simulate_until(10)

        self.assertEqual(fake_service.process.call_count, 1)

    def test_client_stub_definition(self):
        client = self.evaluate(
            Sequence(
                DefineService("Service X", DefineOperation("op", Think(2))),
                DefineClientStub("Client", 10, Query("Service X", "op")),
            )
        ).value
        client.on_success = MagicMock()

        self.simulate_until(26)

        monitor = client.look_up(Symbols.MONITOR)
        self.assertEqual(monitor.tasks.successful, 2)

    def fake_request(self, operation, on_success=lambda: None, on_error=lambda: None):
        request = SQuery(Task(self.fake_client()), operation, 1, lambda s: None)
        request.on_error = on_error
        request.on_success = on_success
        return request

    def fake_service(self, name="DB"):
        fake_service = MagicMock()
        fake_service.name = name
        fake_service.process = MagicMock()
        fake_service.schedule = self.simulation.schedule
        return fake_service

    def fake_client(self):
        fake_client = MagicMock()
        fake_client.schedule = self.simulation.schedule
        fake_client.next_request_id = MagicMock(side_effect=range(1, 100))
        return fake_client

    def _a_service_that_rejects_requests(self):
        def always_reject(request):
            request.reject()

        service = self.fake_service()
        service.process.side_effect = always_reject
        return service

    def _a_service_that_accepts_but_fails(self, after=4):
        def always_accept(request):
            def do_fail():
                request.reply_error()

            request.accept()
            self.simulation._scheduler.after(after, do_fail)

        service = self.fake_service()
        service.process.side_effect = always_accept
        return service

    def _a_service_that_replies_after(self, after=4):
        def always_accept(request):
            def do_succeed():
                request.reply_success()

            request.accept()
            self.simulation._scheduler.after(after, do_succeed)

        service = self.fake_service()
        service.process.side_effect = always_accept
        return service

    def service_that_always_fails(self):
        def always_fail(request):
            request.reply_error()

        service = self.fake_service()
        service.process.side_effect = always_fail
        return service

    def service_that_succeeds_at_attempt(self, successful_attempt):
        attempt = 0

        def respond(request):
            nonlocal attempt
            attempt += 1
            if attempt == successful_attempt:
                request.reply_success()
            else:
                request.reply_error()

        service = self.fake_service()
        service.process.side_effect = respond
        service.schedule = self.simulation.schedule
        return service
Пример #13
0
 def __init__(self):
     self.simulation = Simulation(InMemoryDataStorage(None))
Пример #14
0
 def evaluate(self, expression):
     simulation = Simulation(InMemoryDataStorage(None))
     simulation.evaluate(expression)
     return simulation
Пример #15
0
Файл: ui.py Проект: fchauvel/MAD
 def _simulate(self, expression, arguments):
     simulation = Simulation(self.storage)
     simulation.evaluate(expression)
     simulation.run_until(arguments._time_limit, self.display)
     self.display.simulation_complete(arguments)
     return simulation
Пример #16
0
class ServiceMonitoring(TestCase):
    def setUp(self):
        self.simulation = Simulation(InMemoryDataStorage(None))

    def define(self, symbol, value):
        self.simulation.environment.define(symbol, value)
        return value

    def look_up(self, symbol):
        return self.simulation.environment.look_up(symbol)

    def evaluate(self, expression, continuation=lambda x: x):
        return self.simulation.evaluate(expression, continuation)

    def simulate_until(self, end):
        self.simulation.run_until(end)

    def test_notifies_rejection(self):
        db = self.evaluate(
            DefineService("DB", DefineOperation("Select", Think(5)))).value

        fake_task_pool = MagicMock(ThrottlingPolicyDecorator)
        fake_task_pool._accepts = MagicMock(return_value=False)
        db.tasks = ThrottlingWrapper(db.environment, task_pool=fake_task_pool)

        listener = MagicMock(Listener)
        db.environment.look_up(Symbols.LISTENER).register(listener)

        request1 = self.send_request("DB", "Select")
        request2 = self.send_request("DB", "Select")
        self.simulate_until(10)

        expected_calls = [
            call.arrival_of(request1),
            call.arrival_of(request2),
            call.rejection_of(request2),
            call.success_replied_to(request1)
        ]

        self.assertEqual(expected_calls, listener.method_calls,
                         listener.method_calls)

    def test_notifies_arrival_and_success(self):
        db = self.evaluate(
            DefineService("DB", DefineOperation("Select", Think(5)))).value

        listener = MagicMock(Listener)
        db.environment.look_up(Symbols.LISTENER).register(listener)

        request = self.send_request("DB", "Select")
        self.simulate_until(10)

        expected_calls = [
            call.arrival_of(request),
            call.success_replied_to(request)
        ]

        self.assertEqual(expected_calls, listener.method_calls,
                         listener.method_calls)

    def test_notifies_arrival_and_failure(self):
        db = self.evaluate(
            DefineService("DB", DefineOperation("Select", Fail()))).value

        listener = MagicMock(Listener)
        db.environment.look_up(Symbols.LISTENER).register(listener)

        request = self.send_request("DB", "Select")
        self.simulate_until(10)

        expected_calls = [
            call.arrival_of(request),
            call.error_replied_to(request)
        ]

        self.assertEqual(expected_calls, listener.method_calls,
                         listener.method_calls)

    def test_notifies_when_request_timeout(self):
        db = self.evaluate(
            DefineService("DB", DefineOperation("Select", Fail()))).value

        listener = MagicMock(Listener)
        db.environment.look_up(Symbols.LISTENER).register(listener)

        request = self.send_request("DB", "Select")
        request.reply_error()
        self.simulate_until(40)

        expected_calls = [
            call.arrival_of(request),
            call.error_replied_to(request)
        ]

        self.assertEqual(expected_calls, listener.method_calls,
                         listener.method_calls)

    def send_request(self,
                     service_name,
                     operation_name,
                     on_success=lambda: None,
                     on_error=lambda: None):
        service = self.look_up(service_name)
        request = self.fake_request(operation_name,
                                    on_success=on_success,
                                    on_error=on_error)
        request.send_to(service)
        return request

    def fake_request(self,
                     operation,
                     on_success=lambda: None,
                     on_error=lambda: None):
        return Request(self.fake_client(),
                       0,
                       operation,
                       1,
                       on_success=on_success,
                       on_error=on_error)

    def fake_client(self):
        fake_client = MagicMock()
        fake_client.schedule = self.simulation.schedule
        return fake_client