def suggest_participant(event): """ Returns a suggested participant to be selected by the next wheel spin :param event: Lambda event containing the API Gateway request path parameter wheel_id { "pathParameters": { "wheel_id": string ID of the wheel (DDB Hash Key) }, } :return: response dictionary containing a selected participant_id { "body": { "participant_id": string ID of the suggested participant (DDB Hash Key), "rigged": True (if rigged, otherwise this key is not present) } } """ wheel_id = event['pathParameters']['wheel_id'] wheel = Wheel.get_existing_item(Key={'id': wheel_id}) if 'rigging' in wheel: participant_id = wheel['rigging']['participant_id'] # Use rigging only if the rigged participant is still available if 'Item' in WheelParticipant.get_item(Key={ 'wheel_id': wheel_id, 'id': participant_id }): return_value = {'participant_id': participant_id} # Only return rigged: True if we're not using hidden rigging if not wheel['rigging'].get('hidden', False): return_value['rigged'] = True return return_value return {'participant_id': choice_algorithm.suggest_participant(wheel)}
def test_selection_cycle(mock_dynamodb, setup_data, mock_participant_table): def get_participant_with_id(participants, target_id): for p in participants: if p['id'] == target_id: return p return None rngstate = random.getstate() random.seed(0) # Make the (otherwise pseudorandom) test repeatable. participants = WheelParticipant.scan({})['Items'] wheel = setup_data['wheel'] total_weight_of_chosens = 0 num_iterations = 200 distro = {} for participant in participants: distro[participant['name']] = 0 for _ in range(0, num_iterations): chosen_id = choice_algorithm.suggest_participant(wheel) chosen_was = get_participant_with_id(participants, chosen_id) chosen_was_weight = chosen_was['weight'] distro[chosen_was['name']] = distro[chosen_was['name']] + 1 choice_algorithm.select_participant(wheel, chosen_was) participants = WheelParticipant.scan({})['Items'] chosen_now = get_participant_with_id(participants, chosen_id) chosen_now_weight = chosen_now['weight'] assert chosen_was_weight > 0.0 assert chosen_now_weight == 0 total_weight_of_chosens += chosen_was_weight total_weight = sum( [participant['weight'] for participant in participants]) assert abs(total_weight - len(participants)) < epsilon # Must match human-inspected reasonable values for the RNG seed defined # above for number of times each participant was chosen, and the total # weight of participants selected. These are a rough equivalent to # ensuring that the sequence of chosen participants matches the observed # test run. dv = list(distro.values()) list.sort(dv) human_observed_selection_counts = [26, 27, 27, 29, 29, 31, 31] human_observed_total_weight = 317.8786415239279 assert dv == human_observed_selection_counts assert abs(float(total_weight_of_chosens) - human_observed_total_weight) < epsilon # Put things back the way they were. random.setstate(rngstate)
def test_suggest_participant_no_participants(mock_dynamodb): wheel = {'participant_count': 0} with pytest.raises(BadRequestError): choice_algorithm.suggest_participant(wheel)
def test_suggest_participant(mock_dynamodb, setup_data): participant_ids = [ participant['id'] for participant in setup_data['participants'] ] assert choice_algorithm.suggest_participant( setup_data['wheel']) in participant_ids