예제 #1
0
def wait_for(signal: Signal,
             times_expected: List[float],
             delay_between: float,
             log: List[float] = []):
    for expected in times_expected:
        advance(delay_between)
        signal.wait()
        assert pytest.approx(expected) == now()
        log.append(now())
예제 #2
0
    def __init__(self, sim: Simulator, num: str) -> None:
        self.num = num
        self._num_standing = 0
        self._moment_empty = sim.now()
        self._time_empty = 0
        self._travelers_waiting = Queue()
        self._traveler_ready = Signal()
        self._agents_working = Signal()

        sim.add(self._work_then_break)
        for name in ["alpha", "beta"]:
            sim.add(self._agent_accepting_travelers, name)
예제 #3
0
def test_signal_already_on():
    sim = Simulator()
    signal = Signal().turn_on()
    log = []
    expectation = [1.0]
    sim.add(wait_for, signal, expectation, 1.0, log)
    sim.run()
    assert expectation == log
예제 #4
0
def test_signal_wait_a_while():
    sim = Simulator()
    signal = Signal().turn_off()
    log = []
    expectation = [3.0, 4.0]
    sim.add(wait_for, signal, expectation, 1.0, log)
    sim._schedule(3.0, signal.turn_on)
    sim.run()
    assert expectation == log
예제 #5
0
def test_signal_toggling():
    sim = Simulator()
    signal = Signal().turn_off()
    log = []
    expectation = [3.0, 4.0, 10.0, 13.0, 14.0, 15.0]
    sim.add(wait_for, signal, expectation, 1.0, log)
    sim._schedule(3.0, signal.turn_on)
    sim._schedule(4.5, signal.turn_off)
    sim._schedule(10.0, signal.turn_on)
    sim._schedule(10.1, signal.turn_off)
    sim._schedule(13.0, signal.turn_on)
    sim.run()
    assert expectation == log
예제 #6
0
def test_auto_log_signal(auto_logger):
    def proc(sig):
        local.name = "the-process"
        sig.wait()
        advance(10)
        sig.wait()

    sim = Simulator()
    signal = Signal(name="the-signal").turn_off()
    sim.add(proc, signal)
    sim.run()
    signal.turn_on()
    sim.run()

    check_log(auto_logger,
              (logging.INFO, -1.0, "", "Signal", "the-signal", "turn-off", {}),
              (logging.INFO, 0.0, "", "Simulator", sim.name, "add",
               dict(fn=proc, args=(signal, ), kwargs={})),
              (logging.INFO, 0.0, "", "Simulator", sim.name, "run",
               dict(duration=inf)), (logging.INFO, 0.0, "the-process",
                                     "Signal", "the-signal", "wait", {}),
              (logging.INFO, 0.0, "the-process", "Queue", "the-signal-queue",
               "join", {}), (logging.INFO, 0.0, "the-process", "Process",
                             "the-process", "pause", {}),
              (logging.INFO, 0.0, "", "Simulator", sim.name, "stop", {}),
              (logging.INFO, -1.0, "", "Signal", "the-signal", "turn-on", {}),
              (logging.INFO, -1.0, "", "Queue", "the-signal-queue", "pop",
               dict(process="the-process")),
              (logging.INFO, -1.0, "", "Process", "the-process", "resume", {}),
              (logging.INFO, 0.0, "", "Simulator", sim.name, "run",
               dict(duration=inf)),
              (logging.INFO, 0.0, "the-process", "Process", "the-process",
               "advance", dict(delay=10.0)),
              (logging.INFO, 10.0, "the-process", "Signal", "the-signal",
               "wait", {}), (logging.INFO, 10.0, "the-process", "Process",
                             "the-process", "die-finish", {}),
              (logging.INFO, 10.0, "", "Simulator", sim.name, "stop", {}))
예제 #7
0
def test_select_one_on():
    has_passed = False

    def selecter(sigs: List[Signal]):
        nonlocal has_passed
        select(*sigs)
        has_passed = True

    sim = Simulator()
    signals = [Signal().turn_off() for n in range(5)]
    sim.add(selecter, signals)
    sim.run()
    assert not has_passed
    signals[3].turn_on()
    sim.run()
    assert has_passed
예제 #8
0
def test_signal_waiter_turning_off():
    def waiter_turning_off(signal: Signal, log: List[float]):
        signal.wait()
        signal.turn_off()
        log.append(now())

    sim = Simulator()
    signal = Signal().turn_off()
    log_time = []
    for n in range(5):
        sim.add(waiter_turning_off, signal, log_time)
    schedule_signal_on = [4.0, 9.0, 9.1, 200.0, 3000.0]
    for moment in schedule_signal_on:
        sim._schedule(moment, signal.turn_on)
    sim.run()
    assert schedule_signal_on == pytest.approx(log_time)
예제 #9
0
def test_log_additional_fields(logger):
    def ordeal(queue, signal, resource):
        logger.debug("debug")
        advance(10)
        logger.info("info")
        pause()
        logger.warning("warning")
        queue.join()
        logger.error("error", extra=dict(sim_process="the-process"))
        signal.wait()
        logger.critical("critical")
        resource.take()
        advance(10)
        logger.critical("finish", extra=dict(sim_time=1000.0))
        resource.release()

    def do_resume(proc_ordeal):
        advance(15)
        proc_ordeal.resume()

    def do_pop(queue):
        advance(30)
        queue.pop()

    def do_open(signal):
        advance(50)
        signal.turn_on()

    sim = Simulator()
    queue = Queue()
    signal = Signal().turn_off()
    resource = Resource(1)
    proc_ordeal = sim.add(ordeal, queue, signal, resource)
    name_ordeal = proc_ordeal.local.name
    sim.add(do_resume, proc_ordeal)
    sim.add(do_pop, queue)
    sim.add(do_open, signal)
    sim.run()

    assert [(logging.DEBUG, 0.0, name_ordeal, "debug"),
            (logging.INFO, 10.0, name_ordeal, "info"),
            (logging.WARNING, 15.0, name_ordeal, "warning"),
            (logging.ERROR, 30.0, "the-process", "error"),
            (logging.CRITICAL, 50.0, name_ordeal, "critical"),
            (logging.CRITICAL, 1000.0, name_ordeal, "finish")
            ] == logger.handlers[0].log
예제 #10
0
def test_select_timeout_bad_parameter():
    sigs = [Signal().turn_off() for n in range(5)]
    log = []

    def selecter() -> None:
        try:
            select(*sigs, timeout="asdf")
            log.append(1)
        except Timeout:
            log.append(2)

    def turn_on() -> None:
        advance(25.0)
        sigs[0].turn_on()

    sim = Simulator()
    sim.add(selecter)
    sim.add(turn_on)
    with pytest.raises(ValueError):
        sim.run()
예제 #11
0
def test_select_multiple_turn_on():
    def selecter(sigs: List[Signal], expected: List[bool]) -> None:
        signals_on = select(*sigs)
        for expd, sig in zip(expected, sigs):
            if expd:
                assert sig in signals_on
            else:
                assert sig not in signals_on

    def enabler(delay: float, sig: Signal) -> None:
        advance(delay)
        sig.turn_on()

    sim = Simulator()
    delays = [4.0, 1.0, 3.0, 1.0, 9.0]
    signals = [Signal().turn_off() for n in range(5)]
    for delay, signal in zip(delays, signals):
        sim.add(enabler, delay, signal)
    sim.add(selecter, signals, [delay < 2.0 for delay in delays])
    sim.run()
예제 #12
0
def test_select_timeout():
    sigs = [Signal().turn_off() for n in range(5)]
    log = []

    def selecter() -> None:
        try:
            select(*sigs, timeout=10.0)
            log.append(1)
        except Timeout:
            log.append(2)

    def turn_on() -> None:
        advance(25.0)
        sigs[0].turn_on()

    sim = Simulator()
    sim.add(selecter)
    sim.add(turn_on)
    sim.run()
    assert log == [2]
예제 #13
0
def test_signal_timeout():
    log = []
    signal = Signal().turn_off()

    def wait_then_balk(name: str, delay_balk: float) -> None:
        try:
            signal.wait(delay_balk)
            log.append((name, "finish"))
        except Timeout:
            log.append((name, "balk"))

    def turn_on():
        advance(20.0)
        signal.turn_on()

    sim = Simulator()
    sim.add(wait_then_balk, "a", 10.0)
    sim.add(wait_then_balk, "b", 30.0)
    sim.add(turn_on)
    sim.run()
    assert log == [("a", "balk"), ("b", "finish")]
예제 #14
0
        advance(next(traveler_preparation))

        self._num_standing -= 1
        if self._num_standing == 0:
            debug(f"Belt {self.num} now empty")
            self._moment_empty = now()


def order_traveler(counter: int) -> int:
    return counter + local.priority * 1000000000


# Simulation setup.
sim = Simulator()
main_queue = Queue(order_traveler)
traveler_enters_main_queue = Signal()
traveler_exits_belt = Signal()
belts = [LuggageBodyScanner(sim, n + 1) for n in range(NUM_BELTS)]

log_time_through_checkpoint = []
log_main_queue_empty = []
traveler_name = 0


# Journey of a traveler (hahaha) through the checkpoint.
def traveler():
    global traveler_name
    traveler_name += 1
    name = traveler_name

    local.name = name
예제 #15
0
 def enabler(delay: float, sig: Signal) -> None:
     advance(delay)
     sig.turn_on()
예제 #16
0
class LuggageBodyScanner(object):

    def __init__(self, sim: Simulator, num: str) -> None:
        self.num = num
        self._num_standing = 0
        self._moment_empty = sim.now()
        self._time_empty = 0
        self._travelers_waiting = Queue()
        self._traveler_ready = Signal()
        self._agents_working = Signal()

        sim.add(self._work_then_break)
        for name in ["alpha", "beta"]:
            sim.add(self._agent_accepting_travelers, name)

    def _work_then_break(self) -> None:
        while True:
            advance(next(agent_time_work))
            info(f"Agents on belt {self.num} going on BREAK")
            self._agents_working.turn_off()
            advance(next(agent_time_break))
            info(f"Agents on belt {self.num} coming back to work")
            self._agents_working.turn_on()

    def _agent_accepting_travelers(self, name) -> None:
        agent = Resource(1)  # Models how the agent is busy processing a traveler.
        while True:
            # Are we on break yet? That coffee won't drink itself.
            self._agents_working.wait()
            info(f"Agent {name}/{self.num} ready")

            # Is anybody in there?
            if self._travelers_waiting.is_empty():
                debug(f"Agent {name}/{self.num} waiting for travelers")
                self._traveler_ready.turn_off().wait()
                continue  # Check back if we've gone on break while waiting for somebody.

            # Accept the next traveler traversing the checkpoint.
            traveler_next = self._travelers_waiting.peek()
            debug(f"Agent {name}/{self.num} about to process traveler {traveler_next.local.name}")
            traveler_next.local.agent = agent
            traveler_next.local.agent_name = f"{name}/{self.num}"
            self._travelers_waiting.pop()

            # Allow the next traveler to "use" this agent, so we may then wait until it's done traversing.
            advance(0.0)
            debug(f"Agent {name}/{self.num} doing the processing.")
            with agent.using():
                debug(f"Agent {name}/{self.num} done with the processing.")

    @property
    def num_standing(self) -> int:
        return self._num_standing

    @property
    def time_empty(self) -> float:
        return self._time_empty

    def traverse(self) -> None:
        # Invoked by crossing passengers in order to get through their luggage and body scan.
        me = local.name
        if self._num_standing == 0:
            period_empty = now() - self._moment_empty
            self._time_empty += period_empty
            debug(f"Belt {self.num} -- Empty period: {period_empty:.1f} -- Time empty: {self.time_empty:.1f}")
        self._num_standing += 1
        info(f"Traveler {me} entering belt {self.num}; now {self.num_standing} travelers here")

        # Prepare for check.
        advance(next(traveler_preparation))

        # Wait for an agent to beckon.
        info(f"Traveler {me} (belt {self.num}) prepared and ready for processing")
        self._traveler_ready.turn_on()
        self._travelers_waiting.join()

        with local.agent.using():  # Make agent busy with me.
            # Administer scan or patdown.
            agent_name = Process.current().local.agent_name
            processing_type = next(traveler_processing_type)
            info(f"Traveler {me} processed by agent {agent_name}: {processing_type}")
            advance(next(traveler_processing_time[processing_type]))

        info(f"Traveler {me} (belt {self.num}) buckling back up")
        advance(next(traveler_preparation))

        self._num_standing -= 1
        if self._num_standing == 0:
            debug(f"Belt {self.num} now empty")
            self._moment_empty = now()
예제 #17
0
def turn_on(delay: float, signal: Signal) -> None:
    advance(delay)
    signal.turn_on()
예제 #18
0
 def waiter_turning_off(signal: Signal, log: List[float]):
     signal.wait()
     signal.turn_off()
     log.append(now())