예제 #1
0
    def test_reciprocally_paired(self):
        """ Handling a pair is only done once both have been seen. """
        trip = factories.TripFactory.create(
            algorithm='lottery', program=enums.Program.CLIMBING.value)
        # Two participants, paired with each other!
        john = factories.ParticipantFactory.create()
        alex = factories.ParticipantFactory.create()
        self._reciprocally_pair(john, alex)

        factories.SignUpFactory.create(participant=john, trip=trip)
        factories.SignUpFactory.create(participant=alex, trip=trip)

        john = self._with_annotation(john.pk)
        alex = self._with_annotation(alex.pk)

        runner = run.SingleTripLotteryRunner(trip)

        # John goes first, nothing is done because his partner hasn't been seen!
        john_handler = handle.SingleTripParticipantHandler(john, runner, trip)
        self.assertIsNone(john_handler.place_participant())
        self.assertTrue(runner.seen(john))
        self._assert_on_trip(john, trip, on_trip=False)

        # Once handling Alex, both are placed on their ideal trip.
        alex_handler = handle.SingleTripParticipantHandler(alex, runner, trip)
        alex_handler.place_participant()

        self.assertTrue(runner.seen(alex))
        self._assert_on_trip(john, trip)
        self._assert_on_trip(alex, trip)
        self.assertTrue(runner.handled(alex))
        self.assertTrue(runner.handled(john))
예제 #2
0
    def test_fcfs_not_run(self, save_trip):
        """ If a trip's algorithm is not 'lottery', nothing happens. """
        trip = models.Trip(algorithm='fcfs')
        runner = run.SingleTripLotteryRunner(trip)

        trip.algorithm = 'fcfs'
        runner()  # Early exits because it's not a lottery trip
        save_trip.assert_not_called()
예제 #3
0
    def test_fcfs_not_run(self):
        """If a trip's algorithm is not 'lottery', nothing happens."""
        trip = factories.TripFactory.create(
            algorithm='fcfs', program=enums.Program.HIKING.value
        )
        runner = run.SingleTripLotteryRunner(trip)

        with patch.object(models.Trip, 'save', wraps=models.Trip.save) as save_trip:
            runner()  # Early exits because it's not a lottery trip
        save_trip.assert_not_called()  # Trip was not modified

        trip.refresh_from_db()
        self.assertIsNone(trip.lottery_log)  # No lottery was run!
        self.assertEqual(trip.algorithm, 'fcfs')
예제 #4
0
 def test_run_with_no_signups(self):
     """ We still run the lottery when nobody signed up. """
     trip = factories.TripFactory.create(algorithm='lottery')
     runner = run.SingleTripLotteryRunner(trip)
     runner()
     trip.refresh_from_db()
     expected = '\n'.join([
         'Randomly ordering (preference to MIT affiliates)...',
         'No participants signed up.',
         'Converting trip to first-come, first-serve.',
         '',
     ])
     self.assertEqual(trip.algorithm, 'fcfs')
     self.assertEqual(trip.lottery_log, expected)
예제 #5
0
    def test_run(self):
        """Test a full run of a single trip's lottery, demonstrating deterministic seeding.

        See lottery.rank for more detail on how the random seeding works.
        """
        trip = factories.TripFactory.create(
            pk=838249,  # Will factor into seed + ordering
            name="Single Trip Example",
            algorithm='lottery',
            maximum_participants=2,
            program=enums.Program.CLIMBING.value,
        )

        alice = factories.SignUpFactory.create(
            participant__pk=1021,  # Will factor into seed + ordering
            participant__name="Alice Aaronson",
            participant__affiliation=affiliations.MIT_UNDERGRAD.CODE,
            trip=trip,
            on_trip=False,
        )
        bob = factories.SignUpFactory.create(
            participant__pk=1022,  # Will factor into seed + ordering
            participant__name="Bob Bobberson",
            participant__affiliation=affiliations.MIT_AFFILIATE.CODE,
            trip=trip,
            on_trip=False,
        )
        charles = factories.SignUpFactory.create(
            participant__pk=1023,  # Will factor into seed + ordering
            participant__name="Charles Charleson",
            participant__affiliation=affiliations.NON_AFFILIATE.CODE,
            trip=trip,
            on_trip=False,
        )

        runner = run.SingleTripLotteryRunner(trip)
        runner()  # Early exits because it's not a lottery trip

        # We can expect the exact same ordering & "random" seed because:
        # - we mock wall time to be consistent with every test run
        # - we know participant PKs and the trip PK.
        # - we know the test environment's PRNG_SEED_SECRET
        self.assertEqual(settings.PRNG_SEED_SECRET, 'some-key-unknown-to-participants')
        expected = dedent(
            """\
            Randomly ordering (preference to MIT affiliates)...
            Participants will be handled in the following order:
              1. Alice Aaronson       (MIT undergrad, 0.04993458051632388)
              2. Charles Charleson    (Non-affiliate, 0.1895304657881689)
              3. Bob Bobberson        (MIT affiliate (staff or faculty), 0.5391638258147878)
            --------------------------------------------------
            Single Trip Example has 2 slots, adding Alice Aaronson
            Single Trip Example has 1 slot, adding Charles Charleson
            Adding Bob Bobberson to the waitlist
            """
        )

        # The lottery log explains what happened & is written directly to the trip.
        trip.refresh_from_db()
        self.assertEqual(trip.algorithm, 'fcfs')
        self.assertEqual(trip.lottery_log, expected)

        # Alice & Charles were placed on the trip.
        alice.refresh_from_db()
        self.assertTrue(alice.on_trip)
        charles.refresh_from_db()
        self.assertTrue(charles.on_trip)

        # Bob was waitlisted.
        bob.refresh_from_db()
        self.assertFalse(bob.on_trip)
        self.assertTrue(bob.waitlistsignup)