class Simulator(object): def __init__(self, jobs, num_processors, scheduler): self.event_queue = EventQueue() self.machine = ValidatingMachine(num_processors=num_processors, event_queue=self.event_queue) self.scheduler = scheduler self.event_queue.add_handler(JobSubmissionEvent, self.handle_submission_event) self.event_queue.add_handler(JobTerminationEvent, self.handle_termination_event) for job in jobs: self.event_queue.add_event( JobSubmissionEvent(timestamp = job.submit_time, job = job) ) def run(self): while not self.event_queue.is_empty: self.event_queue.advance() def handle_submission_event(self, event): assert isinstance(event, JobSubmissionEvent) newEvents = self.scheduler.handleSubmissionOfJobEvent(event.job, event.timestamp) for event in newEvents: self.event_queue.add_event(event) def handle_termination_event(self, event): assert isinstance(event, JobTerminationEvent) newEvents = self.scheduler.handleTerminationOfJobEvent(event.job, event.timestamp) for event in newEvents: self.event_queue.add_event(event) def handle_prediction_is_over_event(self, event): assert isinstance(event, JobPredictionIsOverEvent) newEvents = self.scheduler.handlePredictionIsOverEvent(event.job, event.timestamp) for event in newEvents: self.event_queue.add_event(event)
class Simulator(object): def __init__(self, jobs, num_processors, scheduler): self.event_queue = EventQueue() self.machine = ValidatingMachine(num_processors=num_processors, event_queue=self.event_queue) self.scheduler = scheduler self.event_queue.add_handler(JobSubmissionEvent, self.handle_submission_event) self.event_queue.add_handler(JobTerminationEvent, self.handle_termination_event) for job in jobs: self.event_queue.add_event( JobSubmissionEvent(timestamp=job.submit_time, job=job)) def run(self): while not self.event_queue.is_empty: self.event_queue.advance() def handle_submission_event(self, event): assert isinstance(event, JobSubmissionEvent) newEvents = self.scheduler.handleSubmissionOfJobEvent( event.job, event.timestamp) for event in newEvents: self.event_queue.add_event(event) def handle_termination_event(self, event): assert isinstance(event, JobTerminationEvent) newEvents = self.scheduler.handleTerminationOfJobEvent( event.job, event.timestamp) for event in newEvents: self.event_queue.add_event(event) def handle_prediction_is_over_event(self, event): assert isinstance(event, JobPredictionIsOverEvent) newEvents = self.scheduler.handlePredictionIsOverEvent( event.job, event.timestamp) for event in newEvents: self.event_queue.add_event(event)
class test_EventQueue(TestCase): def setUp(self): self.queue = EventQueue() self.event = prototype.JobEvent(timestamp=0, job=None) self.events = [ prototype.JobEvent(timestamp=i, job=None) for i in xrange(10) ] self.handler = _create_handler() def tearDown(self): del self.queue, self.event, self.events, self.handler def test_len_empty(self): self.assertEqual( 0, len(self.queue) ) def test_len_nonempty(self): for event in self.events: self.queue.add_event(event) self.assertEqual( len(self.events), len(self.queue) ) def test_add_event_sanity(self): self.queue.add_event( self.event ) def test_add_event_single_event(self): self.queue.add_event(self.event) self.assertEqual( [self.event], self.queue.sorted_events ) def test_add_same_event_fails(self): self.queue.add_event(self.event) self.assertRaises(Exception, self.queue.add_event, self.event) def test_add_event_simple(self): for event in self.events: self.queue.add_event(event) self.assertEqual( self.events, list(self.queue.sorted_events) ) def test_add_event_sorting(self): random_events = _gen_random_timestamp_events() for event in random_events: self.queue.add_event(event) self.assertEqual( sorted(random_events), self.queue.sorted_events ) def test_remove_event_fails_on_empty(self): self.assertRaises(Exception, self.queue.remove_event, self.event) def test_remove_event_fails_on_missing_event(self): event1 = prototype.JobEvent(0, 0) event2 = prototype.JobEvent(0, 1) assert event1 != event2 # different events self.queue.add_event(event1) self.assertRaises(Exception, self.queue.remove_event, event2) def test_remove_event_succeeds(self): self.queue.add_event(self.event) self.queue.remove_event(self.event) self.failUnless( self.queue.is_empty ) def test_pop_one_job(self): self.queue.add_event( self.event ) assert self.queue.pop() is self.event def test_pop_many_jobs(self): for event in self.events: self.queue.add_event(event) for event in self.events: assert self.queue.pop() is event def test_pop_empty(self): self.assertRaises(AssertionError, self.queue.pop) def test_empty_true(self): self.failUnless( self.queue.is_empty ) def test_empty_false(self): self.queue.add_event( self.event ) self.failIf( self.queue.is_empty ) def test_add_handler_sanity(self): self.queue.add_handler(prototype.JobEvent, self.handler) self.queue.add_event(self.event) self.failIf( self.handler.called ) def test_get_event_handlers_empty(self): self.assertEqual( 0, len(self.queue._get_event_handlers( prototype.JobEvent )) ) def test_get_event_handlers_nonempty(self): self.queue.add_handler(prototype.JobEvent, self.handler) self.assertEqual( 1, len(self.queue._get_event_handlers( prototype.JobEvent )) ) def test_advance_empty_queue(self): self.assertRaises(AssertionError, self.queue.advance) def test_advance_eats_event(self): self._add_event_and_advance(self.event) self.failUnless(self.queue.is_empty) def test_add_event_earlier_event_after_later_advance(self): # after handling an event with a later timestamp, adding an event with # an older timestamp should fail self._add_event_and_advance(prototype.JobEvent(timestamp=2, job="x")) self.assertRaises(Exception, self.queue.add_event, prototype.JobEvent(timestamp=1, job="x")) def test_add_event_same_timestamp_after_advance(self): # same timestamp should succeed even after an event has been handled self._add_event_and_advance(prototype.JobEvent(timestamp=2, job="x")) self.queue.add_event(prototype.JobEvent(timestamp=2, job="y")) def test_advance_one_handler_handles(self): self.queue.add_handler(prototype.JobEvent, self.handler) self._add_event_and_advance(self.event) self.failUnless( self.handler.called ) def test_advance_one_handler_doesnt_handle(self): self.queue.add_handler(prototype.JobStartEvent, self.handler) self._add_event_and_advance(self.event) # JobEvent, different type self.failIf( self.handler.called ) def test_advance_many_handlers(self): matching_handlers = [ _create_handler() for i in xrange(5) ] nonmatching_handlers = [ _create_handler() for i in xrange(5) ] # register handlers that should run for handler in matching_handlers: self.queue.add_handler(prototype.JobEvent, handler) # register handlers that shouldn't run with a different event type for handler in nonmatching_handlers: self.queue.add_handler(prototype.JobStartEvent, handler) self._add_event_and_advance(self.event) for handler in matching_handlers: self.failUnless( handler.called ) for handler in nonmatching_handlers: self.failIf( handler.called ) def test_sometimes_relevant_handler(self): self.queue.add_handler(prototype.JobEvent, self.handler) self._add_event_and_advance(prototype.JobEvent(timestamp=0, job="x")) self.failUnless(self.handler.called) self.handler.called = False self._add_event_and_advance(prototype.JobStartEvent(timestamp=1, job="x")) self.failIf(self.handler.called) self._add_event_and_advance(prototype.JobEvent(timestamp=2, job="x")) self.failUnless(self.handler.called) def _add_event_and_advance(self, event): self.queue.add_event(event) self.queue.advance()
class test_ValidatingMachine(TestCase): def setUp(self): self.event_queue = EventQueue() self.machine = prototype.ValidatingMachine(50, self.event_queue) self.unique_numbers = unique_numbers() def tearDown(self): del self.event_queue, self.machine, self.unique_numbers def _unique_job(self, user_estimated_run_time=100, actual_run_time=60, num_required_processors=20): return prototype.Job( id = self.unique_numbers.next(), user_estimated_run_time = user_estimated_run_time, actual_run_time = actual_run_time, num_required_processors = num_required_processors ) def test_no_jobs_on_init(self): self.assertEqual(0, len(self.machine.jobs)) def test_add_job(self): job = self._unique_job() self.machine._add_job(job, current_timestamp=0) assert job in self.machine.jobs def test_add_several_jobs_success(self): for i in xrange(5): self.machine._add_job( self._unique_job(num_required_processors=5), current_timestamp=0 ) def test_add_job_too_big(self): self.assertRaises(Exception, self.machine._add_job, self._unique_job(num_required_processors=100), current_timestamp=0) def test_add_second_job_too_big(self): self.machine._add_job( self._unique_job(num_required_processors=40), current_timestamp=0 ) self.assertRaises(Exception, self.machine._add_job, self._unique_job(num_required_processors=40), current_timestamp=0 ) def test_free_processors_empty(self): self.assertEqual(50, self.machine.free_processors) def test_free_processors_nonempty(self): for i in xrange(10): self.machine._add_job(self._unique_job(num_required_processors=3), current_timestamp=0) self.assertEqual(20, self.machine.free_processors) def test_free_processors_full(self): self.machine._add_job(self._unique_job(num_required_processors=50), current_timestamp=0) self.assertEqual(0, self.machine.free_processors) def test_busy_processors_empty(self): self.assertEqual(0, self.machine.busy_processors) def test_busy_processors_nonempty(self): for i in xrange(10): self.machine._add_job(self._unique_job(num_required_processors=3), current_timestamp=0) self.assertEqual(30, self.machine.busy_processors) def test_busy_processors_full(self): self.machine._add_job(self._unique_job(num_required_processors=50), current_timestamp=0) self.assertEqual(50, self.machine.busy_processors) def test_add_job_adds_job_end_event(self): self.machine._add_job(self._unique_job(), current_timestamp=0) self.failIf(self.event_queue.is_empty) def test_job_done_removed(self): self.machine._add_job(self._unique_job(), current_timestamp=0) self.event_queue.advance() self.assertEqual(0, self.machine.busy_processors) def test_add_job_different_current_timestamp(self): self.machine._add_job(current_timestamp=100, job=self._unique_job(actual_run_time=20, num_required_processors=10)) self.machine._add_job(current_timestamp=120, job=self._unique_job(actual_run_time=40, num_required_processors=5)) self.event_queue.advance() self.assertEqual(5, self.machine.busy_processors) def test_add_job_different_current_timestamp2(self): self.machine._add_job(current_timestamp=110, job=self._unique_job(actual_run_time=20, num_required_processors=10)) self.machine._add_job(current_timestamp=100, job=self._unique_job(actual_run_time=40, num_required_processors=5)) self.event_queue.advance() self.assertEqual(5, self.machine.busy_processors) def test_start_job_handler(self): job = self._unique_job() self.event_queue.add_event( prototype.JobStartEvent( timestamp=0, job=job ) ) self.event_queue.advance() assert job in self.machine.jobs
class test_EventQueue(TestCase): def setUp(self): self.queue = EventQueue() self.event = prototype.JobEvent(timestamp=0, job=None) self.events = [ prototype.JobEvent(timestamp=i, job=None) for i in xrange(10) ] self.handler = _create_handler() def tearDown(self): del self.queue, self.event, self.events, self.handler def test_len_empty(self): self.assertEqual(0, len(self.queue)) def test_len_nonempty(self): for event in self.events: self.queue.add_event(event) self.assertEqual(len(self.events), len(self.queue)) def test_add_event_sanity(self): self.queue.add_event(self.event) def test_add_event_single_event(self): self.queue.add_event(self.event) self.assertEqual([self.event], self.queue.sorted_events) def test_add_same_event_fails(self): self.queue.add_event(self.event) self.assertRaises(Exception, self.queue.add_event, self.event) def test_add_event_simple(self): for event in self.events: self.queue.add_event(event) self.assertEqual(self.events, list(self.queue.sorted_events)) def test_add_event_sorting(self): random_events = _gen_random_timestamp_events() for event in random_events: self.queue.add_event(event) self.assertEqual(sorted(random_events), self.queue.sorted_events) def test_remove_event_fails_on_empty(self): self.assertRaises(Exception, self.queue.remove_event, self.event) def test_remove_event_fails_on_missing_event(self): event1 = prototype.JobEvent(0, 0) event2 = prototype.JobEvent(0, 1) assert event1 != event2 # different events self.queue.add_event(event1) self.assertRaises(Exception, self.queue.remove_event, event2) def test_remove_event_succeeds(self): self.queue.add_event(self.event) self.queue.remove_event(self.event) self.failUnless(self.queue.is_empty) def test_pop_one_job(self): self.queue.add_event(self.event) assert self.queue.pop() is self.event def test_pop_many_jobs(self): for event in self.events: self.queue.add_event(event) for event in self.events: assert self.queue.pop() is event def test_pop_empty(self): self.assertRaises(AssertionError, self.queue.pop) def test_empty_true(self): self.failUnless(self.queue.is_empty) def test_empty_false(self): self.queue.add_event(self.event) self.failIf(self.queue.is_empty) def test_add_handler_sanity(self): self.queue.add_handler(prototype.JobEvent, self.handler) self.queue.add_event(self.event) self.failIf(self.handler.called) def test_get_event_handlers_empty(self): self.assertEqual( 0, len(self.queue._get_event_handlers(prototype.JobEvent))) def test_get_event_handlers_nonempty(self): self.queue.add_handler(prototype.JobEvent, self.handler) self.assertEqual( 1, len(self.queue._get_event_handlers(prototype.JobEvent))) def test_advance_empty_queue(self): self.assertRaises(AssertionError, self.queue.advance) def test_advance_eats_event(self): self._add_event_and_advance(self.event) self.failUnless(self.queue.is_empty) def test_add_event_earlier_event_after_later_advance(self): # after handling an event with a later timestamp, adding an event with # an older timestamp should fail self._add_event_and_advance(prototype.JobEvent(timestamp=2, job="x")) self.assertRaises(Exception, self.queue.add_event, prototype.JobEvent(timestamp=1, job="x")) def test_add_event_same_timestamp_after_advance(self): # same timestamp should succeed even after an event has been handled self._add_event_and_advance(prototype.JobEvent(timestamp=2, job="x")) self.queue.add_event(prototype.JobEvent(timestamp=2, job="y")) def test_advance_one_handler_handles(self): self.queue.add_handler(prototype.JobEvent, self.handler) self._add_event_and_advance(self.event) self.failUnless(self.handler.called) def test_advance_one_handler_doesnt_handle(self): self.queue.add_handler(prototype.JobStartEvent, self.handler) self._add_event_and_advance(self.event) # JobEvent, different type self.failIf(self.handler.called) def test_advance_many_handlers(self): matching_handlers = [_create_handler() for i in xrange(5)] nonmatching_handlers = [_create_handler() for i in xrange(5)] # register handlers that should run for handler in matching_handlers: self.queue.add_handler(prototype.JobEvent, handler) # register handlers that shouldn't run with a different event type for handler in nonmatching_handlers: self.queue.add_handler(prototype.JobStartEvent, handler) self._add_event_and_advance(self.event) for handler in matching_handlers: self.failUnless(handler.called) for handler in nonmatching_handlers: self.failIf(handler.called) def test_sometimes_relevant_handler(self): self.queue.add_handler(prototype.JobEvent, self.handler) self._add_event_and_advance(prototype.JobEvent(timestamp=0, job="x")) self.failUnless(self.handler.called) self.handler.called = False self._add_event_and_advance( prototype.JobStartEvent(timestamp=1, job="x")) self.failIf(self.handler.called) self._add_event_and_advance(prototype.JobEvent(timestamp=2, job="x")) self.failUnless(self.handler.called) def _add_event_and_advance(self, event): self.queue.add_event(event) self.queue.advance()
class test_ValidatingMachine(TestCase): def setUp(self): self.event_queue = EventQueue() self.machine = prototype.ValidatingMachine(50, self.event_queue) self.unique_numbers = unique_numbers() def tearDown(self): del self.event_queue, self.machine, self.unique_numbers def _unique_job(self, user_estimated_run_time=100, actual_run_time=60, num_required_processors=20): return prototype.Job(id=self.unique_numbers.next(), user_estimated_run_time=user_estimated_run_time, actual_run_time=actual_run_time, num_required_processors=num_required_processors) def test_no_jobs_on_init(self): self.assertEqual(0, len(self.machine.jobs)) def test_add_job(self): job = self._unique_job() self.machine._add_job(job, current_timestamp=0) assert job in self.machine.jobs def test_add_several_jobs_success(self): for i in xrange(5): self.machine._add_job(self._unique_job(num_required_processors=5), current_timestamp=0) def test_add_job_too_big(self): self.assertRaises(Exception, self.machine._add_job, self._unique_job(num_required_processors=100), current_timestamp=0) def test_add_second_job_too_big(self): self.machine._add_job(self._unique_job(num_required_processors=40), current_timestamp=0) self.assertRaises(Exception, self.machine._add_job, self._unique_job(num_required_processors=40), current_timestamp=0) def test_free_processors_empty(self): self.assertEqual(50, self.machine.free_processors) def test_free_processors_nonempty(self): for i in xrange(10): self.machine._add_job(self._unique_job(num_required_processors=3), current_timestamp=0) self.assertEqual(20, self.machine.free_processors) def test_free_processors_full(self): self.machine._add_job(self._unique_job(num_required_processors=50), current_timestamp=0) self.assertEqual(0, self.machine.free_processors) def test_busy_processors_empty(self): self.assertEqual(0, self.machine.busy_processors) def test_busy_processors_nonempty(self): for i in xrange(10): self.machine._add_job(self._unique_job(num_required_processors=3), current_timestamp=0) self.assertEqual(30, self.machine.busy_processors) def test_busy_processors_full(self): self.machine._add_job(self._unique_job(num_required_processors=50), current_timestamp=0) self.assertEqual(50, self.machine.busy_processors) def test_add_job_adds_job_end_event(self): self.machine._add_job(self._unique_job(), current_timestamp=0) self.failIf(self.event_queue.is_empty) def test_job_done_removed(self): self.machine._add_job(self._unique_job(), current_timestamp=0) self.event_queue.advance() self.assertEqual(0, self.machine.busy_processors) def test_add_job_different_current_timestamp(self): self.machine._add_job(current_timestamp=100, job=self._unique_job(actual_run_time=20, num_required_processors=10)) self.machine._add_job(current_timestamp=120, job=self._unique_job(actual_run_time=40, num_required_processors=5)) self.event_queue.advance() self.assertEqual(5, self.machine.busy_processors) def test_add_job_different_current_timestamp2(self): self.machine._add_job(current_timestamp=110, job=self._unique_job(actual_run_time=20, num_required_processors=10)) self.machine._add_job(current_timestamp=100, job=self._unique_job(actual_run_time=40, num_required_processors=5)) self.event_queue.advance() self.assertEqual(5, self.machine.busy_processors) def test_start_job_handler(self): job = self._unique_job() self.event_queue.add_event( prototype.JobStartEvent(timestamp=0, job=job)) self.event_queue.advance() assert job in self.machine.jobs