class TestListDistrictsController(unittest2.TestCase):
    def setUp(self):
        app = webapp2.WSGIApplication([webapp2.Route(r'/<year:>', ApiDistrictListController, methods=['GET'])], debug=True)
        self.testapp = webtest.TestApp(app)

        self.testbed = testbed.Testbed()
        self.testbed.activate()
        self.testbed.init_datastore_v3_stub()
        self.testbed.init_urlfetch_stub()
        self.testbed.init_memcache_stub()
        self.testbed.init_taskqueue_stub(root_path=".")

        self.event = Event(
                id="2010sc",
                name="Palmetto Regional",
                event_type_enum=EventType.DISTRICT_CMP,
                event_district_enum=DistrictType.NEW_ENGLAND,
                short_name="Palmetto",
                event_short="sc",
                year=2010,
                end_date=datetime(2010, 03, 27),
                official=True,
                city="Clemson",
                state_prov="SC",
                country="USA",
                venue="Long Beach Arena",
                venue_address="Long Beach Arena\r\n300 East Ocean Blvd\r\nLong Beach, CA 90802\r\nUSA",
                start_date=datetime(2010, 03, 24),
                webcast_json="[{\"type\": \"twitch\", \"channel\": \"frcgamesense\"}]",
                website="http://www.firstsv.org",
        )
        self.event.put()

        self.event_details = EventDetails(
            id=self.event.key.id(),
            alliance_selections=[
                {"declines": [], "picks": ["frc971", "frc254", "frc1662"]},
                {"declines": [], "picks": ["frc1678", "frc368", "frc4171"]},
                {"declines": [], "picks": ["frc2035", "frc192", "frc4990"]},
                {"declines": [], "picks": ["frc1323", "frc846", "frc2135"]},
                {"declines": [], "picks": ["frc2144", "frc1388", "frc668"]},
                {"declines": [], "picks": ["frc1280", "frc604", "frc100"]},
                {"declines": [], "picks": ["frc114", "frc852", "frc841"]},
                {"declines": [], "picks": ["frc2473", "frc3256", "frc1868"]}
            ]
        )
        self.event_details.put()

    def tearDown(self):
        self.testbed.deactivate()

    def assertDistrictKeys(self, district):
        self.assertEqual(district["key"], DistrictType.type_abbrevs[DistrictType.NEW_ENGLAND])
        self.assertEqual(district["name"], DistrictType.type_names[DistrictType.NEW_ENGLAND])

    def testDistrictApi(self):
        response = self.testapp.get('/{}'.format(self.event.year), headers={"X-TBA-App-Id": "tba-tests:disstrict-controller-test:v01"})

        districts = json.loads(response.body)
        self.assertDistrictKeys(districts[0])
class TestEventStatsApiController(unittest2.TestCase):
    def setUp(self):
        app = webapp2.WSGIApplication([webapp2.Route(r'/<event_key:>', ApiEventStatsController, methods=['GET'])], debug=True)
        self.testapp = webtest.TestApp(app)

        self.testbed = testbed.Testbed()
        self.testbed.activate()
        self.testbed.init_datastore_v3_stub()
        self.testbed.init_urlfetch_stub()
        self.testbed.init_memcache_stub()
        ndb.get_context().clear_cache()  # Prevent data from leaking between tests

        self.testbed.init_taskqueue_stub(root_path=".")

        self.matchstats = {
            "dprs": {"971": 10.52178695299036, "114": 23.7313645955704, "115": 29.559784481082044},
            "oprs": {"971": 91.42946669932006, "114": 59.27751047482864, "115": 13.285278757495144},
            "ccwms": {"971": 80.90767974632955, "114": 35.54614587925829, "115": -16.27450572358693},
        }

        self.event = Event(
                id="2010sc",
                name="Palmetto Regional",
                event_type_enum=EventType.REGIONAL,
                short_name="Palmetto",
                event_short="sc",
                year=2010,
                end_date=datetime(2010, 03, 27),
                official=True,
                city="Clemson",
                state_prov="SC",
                country="USA",
                start_date=datetime(2010, 03, 24)
        )
        self.event.put()

        self.event_details = EventDetails(
            id=self.event.key.id(),
            matchstats=self.matchstats
        )
        self.event_details.put()

    def tearDown(self):
        self.testbed.deactivate()

    def testEventStatsApi(self):
        response = self.testapp.get('/2010sc', headers={"X-TBA-App-Id": "tba-tests:event-controller-test:v01"})

        matchstats = json.loads(response.body)
        self.assertEqual(self.matchstats, matchstats)
class TestEventStatsApiController(unittest2.TestCase):
    def setUp(self):
        app = webapp2.WSGIApplication([webapp2.Route(r'/<event_key:>', ApiEventStatsController, methods=['GET'])], debug=True)
        self.testapp = webtest.TestApp(app)

        self.testbed = testbed.Testbed()
        self.testbed.activate()
        self.testbed.init_datastore_v3_stub()
        self.testbed.init_urlfetch_stub()
        self.testbed.init_memcache_stub()
        self.testbed.init_taskqueue_stub(root_path=".")

        self.matchstats = {
            "dprs": {"971": 10.52178695299036, "114": 23.7313645955704, "115": 29.559784481082044},
            "oprs": {"971": 91.42946669932006, "114": 59.27751047482864, "115": 13.285278757495144},
            "ccwms": {"971": 80.90767974632955, "114": 35.54614587925829, "115": -16.27450572358693},
        }

        self.event = Event(
                id="2010sc",
                name="Palmetto Regional",
                event_type_enum=EventType.REGIONAL,
                short_name="Palmetto",
                event_short="sc",
                year=2010,
                end_date=datetime(2010, 03, 27),
                official=True,
                city="Clemson",
                state_prov="SC",
                country="USA",
                start_date=datetime(2010, 03, 24)
        )
        self.event.put()

        self.event_details = EventDetails(
            id=self.event.key.id(),
            matchstats=self.matchstats
        )
        self.event_details.put()

    def tearDown(self):
        self.testbed.deactivate()

    def testEventStatsApi(self):
        response = self.testapp.get('/2010sc', headers={"X-TBA-App-Id": "tba-tests:event-controller-test:v01"})

        matchstats = json.loads(response.body)
        self.assertEqual(self.matchstats, matchstats)
class TestEventRankingsApiController(unittest2.TestCase):
    def setUp(self):
        app = webapp2.WSGIApplication([webapp2.Route(r'/<event_key:>', ApiEventRankingsController, methods=['GET'])], debug=True)
        self.testapp = webtest.TestApp(app)

        self.testbed = testbed.Testbed()
        self.testbed.activate()
        self.testbed.init_datastore_v3_stub()
        self.testbed.init_urlfetch_stub()
        self.testbed.init_memcache_stub()
        ndb.get_context().clear_cache()  # Prevent data from leaking between tests

        self.testbed.init_taskqueue_stub(root_path=".")

        self.rankings = [
            ["Rank", "Team", "QS", "ASSIST", "AUTO", "T&C", "TELEOP", "Record (W-L-T)", "DQ", "PLAYED"],
            ["1", "1126", "20.00", "240.00", "480.00", "230.00", "478.00", "10-2-0", "0", "12"],
            ["2", "5030", "20.00", "200.00", "290.00", "220.00", "592.00", "10-2-0", "0", "12"],
            ["3", "250", "20.00", "70.00", "415.00", "220.00", "352.00", "10-2-0", "0", "12"]
            ]

        self.event = Event(
                id="2010sc",
                name="Palmetto Regional",
                event_type_enum=EventType.REGIONAL,
                short_name="Palmetto",
                event_short="sc",
                year=2010,
                end_date=datetime(2010, 03, 27),
                official=True,
                city="Clemson",
                state_prov="SC",
                country="USA",
                start_date=datetime(2010, 03, 24)
        )
        self.event.put()

        self.event_details = EventDetails(
            id=self.event.key.id(),
            rankings=self.rankings
        )
        self.event_details.put()

        self.eventNoRanks = Event(
                id="2010ct",
                name="Palmetto Regional",
                event_type_enum=EventType.REGIONAL,
                short_name="Palmetto",
                event_short="ct",
                year=2010,
                end_date=datetime(2010, 03, 27),
                official=True,
                city="Clemson",
                state_prov="SC",
                country="USA",
                start_date=datetime(2010, 03, 24),
        )
        self.eventNoRanks.put()

    def tearDown(self):
        self.testbed.deactivate()

    def testEventRankingsApi(self):
        response = self.testapp.get('/2010sc', headers={"X-TBA-App-Id": "tba-tests:event-controller-test:v01"})

        rankings = json.loads(response.body)
        self.assertEqual(self.rankings, rankings)

    def testEventNoRankingsApi(self):
        response = self.testapp.get('/2010ct', headers={"X-TBA-App-Id": "tba-tests:event-controller-test:v01"})

        self.assertEqual("[]", response.body)
class TestEventApiController(unittest2.TestCase):
    def setUp(self):
        app = webapp2.WSGIApplication([webapp2.Route(r'/<event_key:>', ApiEventController, methods=['GET'])], debug=True)
        self.testapp = webtest.TestApp(app)

        self.testbed = testbed.Testbed()
        self.testbed.activate()
        self.testbed.init_datastore_v3_stub()
        self.testbed.init_urlfetch_stub()
        self.testbed.init_memcache_stub()
        ndb.get_context().clear_cache()  # Prevent data from leaking between tests

        self.testbed.init_taskqueue_stub(root_path=".")

        self.event = Event(
                id="2010sc",
                name="Palmetto Regional",
                event_type_enum=EventType.REGIONAL,
                district_key=None,
                short_name="Palmetto",
                event_short="sc",
                year=2010,
                end_date=datetime(2010, 03, 27),
                official=True,
                city="Clemson",
                state_prov="SC",
                country="USA",
                venue="Long Beach Arena",
                venue_address="Long Beach Arena\r\n300 East Ocean Blvd\r\nLong Beach, CA 90802\r\nUSA",
                timezone_id="America/New_York",
                start_date=datetime(2010, 03, 24),
                webcast_json="[{\"type\": \"twitch\", \"channel\": \"frcgamesense\"}]",
                website="http://www.firstsv.org",
        )
        self.event.put()

        self.event_details = EventDetails(
            id=self.event.key.id(),
            alliance_selections=[
                {"declines": [], "picks": ["frc971", "frc254", "frc1662"]},
                {"declines": [], "picks": ["frc1678", "frc368", "frc4171"]},
                {"declines": [], "picks": ["frc2035", "frc192", "frc4990"]},
                {"declines": [], "picks": ["frc1323", "frc846", "frc2135"]},
                {"declines": [], "picks": ["frc2144", "frc1388", "frc668"]},
                {"declines": [], "picks": ["frc1280", "frc604", "frc100"]},
                {"declines": [], "picks": ["frc114", "frc852", "frc841"]},
                {"declines": [], "picks": ["frc2473", "frc3256", "frc1868"]}
            ]
        )
        self.event_details.put()

    def tearDown(self):
        self.testbed.deactivate()

    def assertEventJson(self, event):
        self.assertEqual(event["key"], self.event.key_name)
        self.assertEqual(event["name"], self.event.name)
        self.assertEqual(event["short_name"], self.event.short_name)
        self.assertEqual(event["official"], self.event.official)
        self.assertEqual(event["event_type_string"], self.event.event_type_str)
        self.assertEqual(event["event_type"], self.event.event_type_enum)
        self.assertEqual(event["event_district_string"], self.event.event_district_str)
        self.assertEqual(event["event_district"], self.event.event_district_enum)
        self.assertEqual(event["start_date"], self.event.start_date.date().isoformat())
        self.assertEqual(event["end_date"], self.event.end_date.date().isoformat())
        self.assertEqual(event["location"], self.event.location)
        self.assertEqual(event["venue_address"], self.event.venue_address.replace('\r\n', '\n'))
        self.assertEqual(event["webcast"], json.loads(self.event.webcast_json))
        self.assertEqual(event["alliances"], self.event.alliance_selections)
        self.assertEqual(event["website"], self.event.website)
        self.assertEqual(event["timezone"], self.event.timezone_id)

    def testEventApi(self):
        response = self.testapp.get('/2010sc', headers={"X-TBA-App-Id": "tba-tests:event-controller-test:v01"})

        event_dict = json.loads(response.body)
        self.assertEventJson(event_dict)
class TestEventRankingsApiController(unittest2.TestCase):
    def setUp(self):
        app = webapp2.WSGIApplication([webapp2.Route(r'/<event_key:>', ApiEventRankingsController, methods=['GET'])], debug=True)
        self.testapp = webtest.TestApp(app)

        self.testbed = testbed.Testbed()
        self.testbed.activate()
        self.testbed.init_datastore_v3_stub()
        self.testbed.init_urlfetch_stub()
        self.testbed.init_memcache_stub()
        self.testbed.init_taskqueue_stub(root_path=".")

        self.rankings = [
            ["Rank", "Team", "QS", "ASSIST", "AUTO", "T&C", "TELEOP", "Record (W-L-T)", "DQ", "PLAYED"],
            ["1", "1126", "20.00", "240.00", "480.00", "230.00", "478.00", "10-2-0", "0", "12"],
            ["2", "5030", "20.00", "200.00", "290.00", "220.00", "592.00", "10-2-0", "0", "12"],
            ["3", "250", "20.00", "70.00", "415.00", "220.00", "352.00", "10-2-0", "0", "12"]
            ]

        self.event = Event(
                id="2010sc",
                name="Palmetto Regional",
                event_type_enum=EventType.REGIONAL,
                short_name="Palmetto",
                event_short="sc",
                year=2010,
                end_date=datetime(2010, 03, 27),
                official=True,
                city="Clemson",
                state_prov="SC",
                country="USA",
                start_date=datetime(2010, 03, 24)
        )
        self.event.put()

        self.event_details = EventDetails(
            id=self.event.key.id(),
            rankings=self.rankings
        )
        self.event_details.put()

        self.eventNoRanks = Event(
                id="2010ct",
                name="Palmetto Regional",
                event_type_enum=EventType.REGIONAL,
                short_name="Palmetto",
                event_short="ct",
                year=2010,
                end_date=datetime(2010, 03, 27),
                official=True,
                city="Clemson",
                state_prov="SC",
                country="USA",
                start_date=datetime(2010, 03, 24),
        )
        self.eventNoRanks.put()

    def tearDown(self):
        self.testbed.deactivate()

    def testEventRankingsApi(self):
        response = self.testapp.get('/2010sc', headers={"X-TBA-App-Id": "tba-tests:event-controller-test:v01"})

        rankings = json.loads(response.body)
        self.assertEqual(self.rankings, rankings)

    def testEventNoRankingsApi(self):
        response = self.testapp.get('/2010ct', headers={"X-TBA-App-Id": "tba-tests:event-controller-test:v01"})

        self.assertEqual("[]", response.body)
class TestEventApiController(unittest2.TestCase):
    def setUp(self):
        app = webapp2.WSGIApplication([webapp2.Route(r'/<event_key:>', ApiEventController, methods=['GET'])], debug=True)
        self.testapp = webtest.TestApp(app)

        self.testbed = testbed.Testbed()
        self.testbed.activate()
        self.testbed.init_datastore_v3_stub()
        self.testbed.init_urlfetch_stub()
        self.testbed.init_memcache_stub()
        self.testbed.init_taskqueue_stub(root_path=".")

        self.event = Event(
                id="2010sc",
                name="Palmetto Regional",
                event_type_enum=EventType.REGIONAL,
                event_district_enum=DistrictType.NO_DISTRICT,
                short_name="Palmetto",
                event_short="sc",
                year=2010,
                end_date=datetime(2010, 03, 27),
                official=True,
                city="Clemson",
                state_prov="SC",
                country="USA",
                venue="Long Beach Arena",
                venue_address="Long Beach Arena\r\n300 East Ocean Blvd\r\nLong Beach, CA 90802\r\nUSA",
                timezone_id="America/New_York",
                start_date=datetime(2010, 03, 24),
                webcast_json="[{\"type\": \"twitch\", \"channel\": \"frcgamesense\"}]",
                website="http://www.firstsv.org",
        )
        self.event.put()

        self.event_details = EventDetails(
            id=self.event.key.id(),
            alliance_selections=[
                {"declines": [], "picks": ["frc971", "frc254", "frc1662"]},
                {"declines": [], "picks": ["frc1678", "frc368", "frc4171"]},
                {"declines": [], "picks": ["frc2035", "frc192", "frc4990"]},
                {"declines": [], "picks": ["frc1323", "frc846", "frc2135"]},
                {"declines": [], "picks": ["frc2144", "frc1388", "frc668"]},
                {"declines": [], "picks": ["frc1280", "frc604", "frc100"]},
                {"declines": [], "picks": ["frc114", "frc852", "frc841"]},
                {"declines": [], "picks": ["frc2473", "frc3256", "frc1868"]}
            ]
        )
        self.event_details.put()

    def tearDown(self):
        self.testbed.deactivate()

    def assertEventJson(self, event):
        self.assertEqual(event["key"], self.event.key_name)
        self.assertEqual(event["name"], self.event.name)
        self.assertEqual(event["short_name"], self.event.short_name)
        self.assertEqual(event["official"], self.event.official)
        self.assertEqual(event["event_type_string"], self.event.event_type_str)
        self.assertEqual(event["event_type"], self.event.event_type_enum)
        self.assertEqual(event["event_district_string"], self.event.event_district_str)
        self.assertEqual(event["event_district"], self.event.event_district_enum)
        self.assertEqual(event["start_date"], self.event.start_date.date().isoformat())
        self.assertEqual(event["end_date"], self.event.end_date.date().isoformat())
        self.assertEqual(event["location"], self.event.location)
        self.assertEqual(event["venue_address"], self.event.venue_address.replace('\r\n', '\n'))
        self.assertEqual(event["webcast"], json.loads(self.event.webcast_json))
        self.assertEqual(event["alliances"], self.event.alliance_selections)
        self.assertEqual(event["website"], self.event.website)
        self.assertEqual(event["timezone"], self.event.timezone_id)

    def testEventApi(self):
        response = self.testapp.get('/2010sc', headers={"X-TBA-App-Id": "tba-tests:event-controller-test:v01"})

        event_dict = json.loads(response.body)
        self.assertEventJson(event_dict)
class TestEventDetailsManipulator(unittest2.TestCase):
    def setUp(self):
        self.testbed = testbed.Testbed()
        self.testbed.activate()
        self.testbed.init_datastore_v3_stub()
        self.testbed.init_taskqueue_stub(root_path=".")
        self.testbed.init_memcache_stub()
        self.maxDiff = None

        with open('test_data/usfirst_html/usfirst_event_rankings_2012ct.html', 'r') as f:
            good_rankings, _ = UsfirstEventRankingsParser.parse(f.read())

        with open('test_data/usfirst_html/usfirst_event_rankings_2012ct_bad.html', 'r') as f:
            bad_rankings, _ = UsfirstEventRankingsParser.parse(f.read())

        self.old_alliance_selections = {
            '1': {'picks': ['frc254', 'frc469', 'frc2848', 'frc74'], 'declines':[] },
            '2': {'picks': ['frc1718', 'frc2451', 'frc573', 'frc2016'], 'declines':[] },
            '3': {'picks': ['frc2928', 'frc2013', 'frc1311', 'frc842'], 'declines':[] },
            '4': {'picks': ['frc180', 'frc125', 'frc1323', 'frc2468'], 'declines':[] },
            '5': {'picks': ['frc118', 'frc359', 'frc4334', 'frc865'], 'declines':[] },
            '6': {'picks': ['frc135', 'frc1241', 'frc11', 'frc68'], 'declines':[] },
            '7': {'picks': ['frc3478', 'frc177', 'frc294', 'frc230'], 'declines':[] },
            '8': {'picks': ['frc624', 'frc987', 'frc3476', 'frc123'], 'declines':[] },
        }

        self.new_alliance_selections = {
            '1': {'picks': ['frc254', 'frc469', 'frc2848', 'frc74'], 'declines':[] },
            '2': {'picks': ['frc1718', 'frc2451', 'frc573', 'frc2016'], 'declines':[] },
            '3': {'picks': ['frc2928', 'frc2013', 'frc1311', 'frc842'], 'declines':[] },
            '4': {'picks': ['frc180', 'frc125', 'frc1323', 'frc2468'], 'declines':[] },
            '5': {'picks': ['frc118', 'frc359', 'frc4334', 'frc865'], 'declines':[] },
            '6': {'picks': ['frc135', 'frc1241', 'frc11', 'frc68'], 'declines':[] },
            '7': {'picks': ['frc3478', 'frc177', 'frc294', 'frc230'], 'declines':[] },
            '8': {'picks': ['frc624', 'frc987', 'frc3476', 'frc3015'], 'declines':[] },
        }

        self.old_event_details = EventDetails(
            id='2011ct',
            rankings=good_rankings,
            alliance_selections=self.old_alliance_selections,
        )

        self.new_event_details = EventDetails(
            id='2011ct',
            rankings=bad_rankings,
            alliance_selections=self.new_alliance_selections,
            matchstats={'oprs': {'4255': 7.4877151786460301, '2643': 27.285682906835952, '852': 10.452538750544525, '4159': 25.820137009871139, '581': 18.513816255143144}}
        )

    def tearDown(self):
        self.testbed.deactivate()

    def assertMergedEventDetails(self, event_details):
        self.assertOldEventDetails(event_details)
        self.assertEqual(event_details.matchstats, {'oprs': {'4255': 7.4877151786460301, '2643': 27.285682906835952, '852': 10.452538750544525, '4159': 25.820137009871139, '581': 18.513816255143144}})
        self.assertEqual(event_details.rankings, [['Rank', 'Team', 'QS', 'HP', 'BP', 'TP', 'CP', 'Record (W-L-T)', 'DQ', 'Played'], ['1', '2168', '32.00', '147.00', '60.00', '208.00', '14', '9-1-0', '0', '10'], ['2', '118', '31.00', '168.00', '90.00', '231.00', '17', '7-3-0', '0', '10'], ['3', '177', '30.00', '177.00', '120.00', '151.00', '14', '8-2-0', '0', '10'], ['4', '195', '29.00', '116.00', '70.00', '190.00', '16', '6-3-1', '0', '10'], ['5', '237', '28.00', '120.00', '60.00', '123.00', '14', '7-3-0', '0', '10'], ['6', '1071', '28.00', '115.00', '120.00', '142.00', '10', '9-1-0', '0', '10'], ['7', '173', '28.00', '114.00', '110.00', '108.00', '14', '7-3-0', '0', '10'], ['8', '1073', '28.00', '110.00', '100.00', '152.00', '11', '8-1-1', '0', '10'], ['9', '694', '28.00', '78.00', '100.00', '140.00', '14', '7-3-0', '0', '10'], ['10', '558', '27.00', '152.00', '100.00', '145.00', '13', '7-3-0', '0', '10'], ['11', '175', '27.00', '141.00', '160.00', '117.00', '13', '7-3-0', '0', '10'], ['12', '181', '26.00', '151.00', '70.00', '95.00', '14', '6-4-0', '0', '10'], ['13', '176', '26.00', '120.00', '60.00', '90.00', '18', '4-6-0', '0', '10'], ['14', '1511', '26.00', '111.00', '80.00', '164.00', '14', '6-4-0', '0', '10'], ['15', '126', '26.00', '108.00', '70.00', '165.00', '14', '6-4-0', '0', '10'], ['16', '4122', '26.00', '92.00', '100.00', '78.00', '14', '6-4-0', '0', '10'], ['17', '869', '25.00', '68.00', '130.00', '75.00', '12', '6-3-1', '0', '10'], ['18', '3464', '24.00', '135.00', '80.00', '109.00', '14', '5-5-0', '0', '10'], ['19', '3467', '24.00', '101.00', '80.00', '123.00', '10', '7-3-0', '0', '10'], ['20', '3718', '24.00', '100.00', '60.00', '106.00', '12', '6-4-0', '0', '10'], ['21', '3461', '24.00', '79.00', '30.00', '94.00', '14', '5-5-0', '0', '10'], ['22', '4055', '24.00', '78.00', '80.00', '79.00', '16', '4-6-0', '0', '10'], ['23', '1922', '23.00', '114.00', '110.00', '151.00', '10', '6-3-1', '0', '10'], ['24', '95', '22.00', '120.00', '70.00', '123.00', '14', '4-6-0', '0', '10'], ['25', '1991', '22.00', '113.00', '100.00', '58.00', '12', '5-5-0', '0', '10'], ['26', '839', '22.00', '96.00', '110.00', '136.00', '10', '6-4-0', '0', '10'], ['27', '1099', '21.00', '126.00', '110.00', '97.00', '8', '6-3-1', '0', '10'], ['28', '230', '20.00', '143.00', '80.00', '104.00', '8', '6-4-0', '0', '10'], ['29', '3017', '20.00', '134.00', '50.00', '88.00', '12', '4-6-0', '0', '10'], ['30', '2067', '20.00', '128.00', '80.00', '122.00', '10', '5-5-0', '0', '10'], ['31', '250', '20.00', '118.00', '40.00', '99.00', '10', '5-5-0', '0', '10'], ['32', '155', '20.00', '100.00', '50.00', '74.00', '12', '4-6-0', '0', '10'], ['33', '236', '20.00', '99.00', '20.00', '126.00', '10', '5-5-0', '0', '10'], ['34', '1124', '20.00', '92.00', '80.00', '109.00', '8', '6-4-0', '0', '10'], ['35', '3146', '20.00', '81.00', '110.00', '81.00', '6', '7-3-0', '0', '10'], ['36', '663', '20.00', '71.00', '90.00', '90.00', '12', '4-6-0', '0', '10'], ['37', '1699', '20.00', '70.00', '80.00', '139.00', '12', '4-6-0', '0', '10'], ['38', '1027', '20.00', '53.00', '70.00', '97.00', '12', '4-6-0', '0', '10'], ['39', '20', '19.00', '79.00', '70.00', '106.00', '9', '5-5-0', '0', '10'], ['40', '3182', '18.00', '108.00', '60.00', '147.00', '8', '5-5-0', '0', '10'], ['41', '229', '18.00', '97.00', '40.00', '153.00', '10', '4-6-0', '0', '10'], ['42', '1665', '18.00', '95.00', '120.00', '106.00', '10', '4-6-0', '0', '10'], ['43', '228', '18.00', '81.00', '60.00', '163.00', '10', '4-6-0', '0', '10'], ['44', '178', '18.00', '81.00', '50.00', '58.00', '12', '3-7-0', '0', '10'], ['45', '1740', '18.00', '62.00', '20.00', '99.00', '8', '5-5-0', '0', '10'], ['46', '3634', '18.00', '54.00', '30.00', '105.00', '10', '4-6-0', '0', '10'], ['47', '2791', '18.00', '53.00', '100.00', '108.00', '10', '4-6-0', '0', '10'], ['48', '571', '18.00', '53.00', '70.00', '109.00', '10', '4-6-0', '0', '10'], ['49', '2170', '17.00', '89.00', '60.00', '103.00', '9', '4-5-0', '1', '10'], ['50', '1493', '16.00', '150.00', '60.00', '132.00', '6', '5-5-0', '0', '10'], ['51', '549', '16.00', '129.00', '100.00', '91.00', '6', '5-5-0', '0', '10'], ['52', '743', '16.00', '70.00', '30.00', '67.00', '10', '3-7-0', '0', '10'], ['53', '2836', '16.00', '64.00', '80.00', '126.00', '8', '4-6-0', '0', '10'], ['54', '999', '14.00', '114.00', '20.00', '79.00', '10', '2-8-0', '0', '10'], ['55', '3525', '14.00', '109.00', '40.00', '66.00', '6', '4-6-0', '0', '10'], ['56', '3104', '14.00', '92.00', '20.00', '80.00', '6', '4-6-0', '0', '10'], ['57', '3555', '14.00', '68.00', '60.00', '68.00', '8', '3-7-0', '0', '10'], ['58', '4134', '13.00', '96.00', '30.00', '80.00', '6', '3-6-1', '0', '10'], ['59', '1559', '12.00', '110.00', '10.00', '94.00', '8', '2-8-0', '0', '10'], ['60', '3719', '12.00', '97.00', '60.00', '95.00', '6', '3-7-0', '0', '10'], ['61', '3654', '12.00', '59.00', '20.00', '57.00', '8', '2-8-0', '0', '10'], ['62', '2785', '12.00', '41.00', '70.00', '96.00', '8', '2-8-0', '0', '10'], ['63', '1880', '10.00', '57.00', '40.00', '86.00', '6', '2-8-0', '0', '10'], ['64', '1784', '10.00', '44.00', '40.00', '60.00', '6', '2-7-0', '1', '10']])
        self.assertEqual(event_details.alliance_selections, self.new_alliance_selections)

    def assertOldEventDetails(self, event_details):
        self.assertEqual(event_details.key.id(), "2011ct")

    def test_createOrUpdate(self):
        EventDetailsManipulator.createOrUpdate(self.old_event_details)
        self.assertOldEventDetails(EventDetails.get_by_id('2011ct'))
        EventDetailsManipulator.createOrUpdate(self.new_event_details)
        self.assertMergedEventDetails(EventDetails.get_by_id('2011ct'))

    def test_findOrSpawn(self):
        self.old_event_details.put()
        self.assertMergedEventDetails(EventDetailsManipulator.findOrSpawn(self.new_event_details))

    def test_updateMerge(self):
        self.assertMergedEventDetails(EventDetailsManipulator.updateMerge(self.new_event_details, self.old_event_details))
class TestEventController(unittest2.TestCase):

    def setUp(self):
        self.testbed = testbed.Testbed()
        self.testbed.activate()
        self.testbed.init_datastore_v3_stub()
        self.testbed.init_memcache_stub()
        ndb.get_context().clear_cache()  # Prevent data from leaking between tests

        app = webapp2.WSGIApplication([
            RedirectRoute(r'/event/<event_key>', EventDetail, 'event-detail'),
            RedirectRoute(r'/event/<event_key>/insights', EventInsights, 'event-insights'),
            RedirectRoute(r'/events/<year:[0-9]+>', EventList, 'event-list-year'),
            RedirectRoute(r'/events', EventList, 'event-list'),
        ])
        self.testapp = webtest.TestApp(app)

        self.event1 = Event(
                id="2016necmp",
                name="New England District Championship",
                event_type_enum=EventType.DISTRICT_CMP,
                event_district_enum=DistrictType.NEW_ENGLAND,
                short_name="New England",
                event_short="necmp",
                year=2016,
                end_date=datetime(2016, 03, 27),
                official=True,
                city='Hartford',
                state_prov='CT',
                country='USA',
                venue="Some Venue",
                venue_address="Some Venue, Hartford, CT, USA",
                timezone_id="America/New_York",
                start_date=datetime(2016, 03, 24),
                webcast_json="[{\"type\": \"twitch\", \"channel\": \"frcgamesense\"}]",
                website="http://www.firstsv.org",
        )
        this_year = datetime.now().year
        self.event2 = Event(
                id="2016necmp",
                name="New England District Championship",
                event_type_enum=EventType.DISTRICT_CMP,
                event_district_enum=DistrictType.NEW_ENGLAND,
                short_name="New England",
                event_short="necmp",
                year=this_year,
                end_date=datetime(this_year, 03, 27),
                official=True,
                city='Hartford',
                state_prov='CT',
                country='USA',
                venue="Some Venue",
                venue_address="Some Venue, Hartford, CT, USA",
                timezone_id="America/New_York",
                start_date=datetime(this_year, 03, 24),
                webcast_json="[{\"type\": \"twitch\", \"channel\": \"frcgamesense\"}]",
                website="http://www.firstsv.org",
        )
        self.event1.put()
        self.event2.put()

        self.event1_details = EventDetails(
            id=self.event1.key.id(),
            predictions={"ranking_prediction_stats": None, "match_predictions": None, "ranking_predictions": None, "match_prediction_stats": None}
        )
        self.event1_details.put()

        self.event2_details = EventDetails(
            id=self.event2.key.id(),
            predictions={"ranking_prediction_stats": None, "match_predictions": None, "ranking_predictions": None, "match_prediction_stats": None}
        )
        self.event2_details.put()

    def tearDown(self):
        self.testbed.deactivate()

    def testEventListDefaultYear(self):
        response = self.testapp.get("/events")
        self.assertEqual(response.status_int, 200)

    def testEventListExplicitYear(self):
        response = self.testapp.get("/events/2015")
        self.assertEqual(response.status_int, 200)

    def testEventListNoEvents(self):
        response = self.testapp.get("/events/2014")
        self.assertEqual(response.status_int, 200)

    def testEventDetails(self):
        response = self.testapp.get("/event/2016necmp")
        self.assertEqual(response.status_int, 200)

    def testEventDetailsNotFound(self):
        response = self.testapp.get("/event/2016meow", status=404)
        self.assertEqual(response.status_int, 404)

    def testEventInsights(self):
        response = self.testapp.get("/event/2016necmp/insights")
        self.assertEqual(response.status_int, 200)

    def testEventInsightsNotFound(self):
        response = self.testapp.get("/event/2016meow/insights", status=404)
        self.assertEqual(response.status_int, 404)
示例#10
0
class TestListDistrictsController(unittest2.TestCase):
    def setUp(self):
        app = webapp2.WSGIApplication([webapp2.Route(r'/<year:>', ApiDistrictListController, methods=['GET'])], debug=True)
        self.testapp = webtest.TestApp(app)

        self.testbed = testbed.Testbed()
        self.testbed.activate()
        self.testbed.init_datastore_v3_stub()
        self.testbed.init_urlfetch_stub()
        self.testbed.init_memcache_stub()
        ndb.get_context().clear_cache()  # Prevent data from leaking between tests

        self.testbed.init_taskqueue_stub(root_path=".")

        self.event = Event(
                id="2010sc",
                name="Palmetto Regional",
                event_type_enum=EventType.DISTRICT_CMP,
                event_district_enum=DistrictType.NEW_ENGLAND,
                short_name="Palmetto",
                event_short="sc",
                year=2010,
                end_date=datetime(2010, 03, 27),
                official=True,
                city="Clemson",
                state_prov="SC",
                country="USA",
                venue="Long Beach Arena",
                venue_address="Long Beach Arena\r\n300 East Ocean Blvd\r\nLong Beach, CA 90802\r\nUSA",
                start_date=datetime(2010, 03, 24),
                webcast_json="[{\"type\": \"twitch\", \"channel\": \"frcgamesense\"}]",
                website="http://www.firstsv.org",
        )
        self.event.put()

        self.event_details = EventDetails(
            id=self.event.key.id(),
            alliance_selections=[
                {"declines": [], "picks": ["frc971", "frc254", "frc1662"]},
                {"declines": [], "picks": ["frc1678", "frc368", "frc4171"]},
                {"declines": [], "picks": ["frc2035", "frc192", "frc4990"]},
                {"declines": [], "picks": ["frc1323", "frc846", "frc2135"]},
                {"declines": [], "picks": ["frc2144", "frc1388", "frc668"]},
                {"declines": [], "picks": ["frc1280", "frc604", "frc100"]},
                {"declines": [], "picks": ["frc114", "frc852", "frc841"]},
                {"declines": [], "picks": ["frc2473", "frc3256", "frc1868"]}
            ]
        )
        self.event_details.put()

    def tearDown(self):
        self.testbed.deactivate()

    def assertDistrictKeys(self, district):
        self.assertEqual(district["key"], DistrictType.type_abbrevs[DistrictType.NEW_ENGLAND])
        self.assertEqual(district["name"], DistrictType.type_names[DistrictType.NEW_ENGLAND])

    def testDistrictApi(self):
        response = self.testapp.get('/{}'.format(self.event.year), headers={"X-TBA-App-Id": "tba-tests:disstrict-controller-test:v01"})

        districts = json.loads(response.body)
        self.assertDistrictKeys(districts[0])
示例#11
0
class TestEventDetailsManipulator(unittest2.TestCase):
    def setUp(self):
        self.testbed = testbed.Testbed()
        self.testbed.activate()
        self.testbed.init_datastore_v3_stub()
        self.testbed.init_taskqueue_stub(root_path=".")
        self.testbed.init_memcache_stub()
        ndb.get_context().clear_cache(
        )  # Prevent data from leaking between tests

        self.maxDiff = None

        with open('test_data/usfirst_html/usfirst_event_rankings_2012ct.html',
                  'r') as f:
            good_rankings, _ = UsfirstEventRankingsParser.parse(f.read())

        with open(
                'test_data/usfirst_html/usfirst_event_rankings_2012ct_bad.html',
                'r') as f:
            bad_rankings, _ = UsfirstEventRankingsParser.parse(f.read())

        self.old_alliance_selections = {
            '1': {
                'picks': ['frc254', 'frc469', 'frc2848', 'frc74'],
                'declines': []
            },
            '2': {
                'picks': ['frc1718', 'frc2451', 'frc573', 'frc2016'],
                'declines': []
            },
            '3': {
                'picks': ['frc2928', 'frc2013', 'frc1311', 'frc842'],
                'declines': []
            },
            '4': {
                'picks': ['frc180', 'frc125', 'frc1323', 'frc2468'],
                'declines': []
            },
            '5': {
                'picks': ['frc118', 'frc359', 'frc4334', 'frc865'],
                'declines': []
            },
            '6': {
                'picks': ['frc135', 'frc1241', 'frc11', 'frc68'],
                'declines': []
            },
            '7': {
                'picks': ['frc3478', 'frc177', 'frc294', 'frc230'],
                'declines': []
            },
            '8': {
                'picks': ['frc624', 'frc987', 'frc3476', 'frc123'],
                'declines': []
            },
        }

        self.new_alliance_selections = {
            '1': {
                'picks': ['frc254', 'frc469', 'frc2848', 'frc74'],
                'declines': []
            },
            '2': {
                'picks': ['frc1718', 'frc2451', 'frc573', 'frc2016'],
                'declines': []
            },
            '3': {
                'picks': ['frc2928', 'frc2013', 'frc1311', 'frc842'],
                'declines': []
            },
            '4': {
                'picks': ['frc180', 'frc125', 'frc1323', 'frc2468'],
                'declines': []
            },
            '5': {
                'picks': ['frc118', 'frc359', 'frc4334', 'frc865'],
                'declines': []
            },
            '6': {
                'picks': ['frc135', 'frc1241', 'frc11', 'frc68'],
                'declines': []
            },
            '7': {
                'picks': ['frc3478', 'frc177', 'frc294', 'frc230'],
                'declines': []
            },
            '8': {
                'picks': ['frc624', 'frc987', 'frc3476', 'frc3015'],
                'declines': []
            },
        }

        self.old_event_details = EventDetails(
            id='2011ct',
            rankings=good_rankings,
            alliance_selections=self.old_alliance_selections,
        )

        self.new_event_details = EventDetails(
            id='2011ct',
            rankings=bad_rankings,
            alliance_selections=self.new_alliance_selections,
            matchstats={
                'oprs': {
                    '4255': 7.4877151786460301,
                    '2643': 27.285682906835952,
                    '852': 10.452538750544525,
                    '4159': 25.820137009871139,
                    '581': 18.513816255143144
                }
            })

    def tearDown(self):
        self.testbed.deactivate()

    def assertMergedEventDetails(self, event_details):
        self.assertOldEventDetails(event_details)
        self.assertEqual(
            event_details.matchstats, {
                'oprs': {
                    '4255': 7.4877151786460301,
                    '2643': 27.285682906835952,
                    '852': 10.452538750544525,
                    '4159': 25.820137009871139,
                    '581': 18.513816255143144
                }
            })
        self.assertEqual(event_details.rankings,
                         [[
                             'Rank', 'Team', 'QS', 'HP', 'BP', 'TP', 'CP',
                             'Record (W-L-T)', 'DQ', 'Played'
                         ],
                          [
                              '1', '2168', '32.00', '147.00', '60.00',
                              '208.00', '14', '9-1-0', '0', '10'
                          ],
                          [
                              '2', '118', '31.00', '168.00', '90.00', '231.00',
                              '17', '7-3-0', '0', '10'
                          ],
                          [
                              '3', '177', '30.00', '177.00', '120.00',
                              '151.00', '14', '8-2-0', '0', '10'
                          ],
                          [
                              '4', '195', '29.00', '116.00', '70.00', '190.00',
                              '16', '6-3-1', '0', '10'
                          ],
                          [
                              '5', '237', '28.00', '120.00', '60.00', '123.00',
                              '14', '7-3-0', '0', '10'
                          ],
                          [
                              '6', '1071', '28.00', '115.00', '120.00',
                              '142.00', '10', '9-1-0', '0', '10'
                          ],
                          [
                              '7', '173', '28.00', '114.00', '110.00',
                              '108.00', '14', '7-3-0', '0', '10'
                          ],
                          [
                              '8', '1073', '28.00', '110.00', '100.00',
                              '152.00', '11', '8-1-1', '0', '10'
                          ],
                          [
                              '9', '694', '28.00', '78.00', '100.00', '140.00',
                              '14', '7-3-0', '0', '10'
                          ],
                          [
                              '10', '558', '27.00', '152.00', '100.00',
                              '145.00', '13', '7-3-0', '0', '10'
                          ],
                          [
                              '11', '175', '27.00', '141.00', '160.00',
                              '117.00', '13', '7-3-0', '0', '10'
                          ],
                          [
                              '12', '181', '26.00', '151.00', '70.00', '95.00',
                              '14', '6-4-0', '0', '10'
                          ],
                          [
                              '13', '176', '26.00', '120.00', '60.00', '90.00',
                              '18', '4-6-0', '0', '10'
                          ],
                          [
                              '14', '1511', '26.00', '111.00', '80.00',
                              '164.00', '14', '6-4-0', '0', '10'
                          ],
                          [
                              '15', '126', '26.00', '108.00', '70.00',
                              '165.00', '14', '6-4-0', '0', '10'
                          ],
                          [
                              '16', '4122', '26.00', '92.00', '100.00',
                              '78.00', '14', '6-4-0', '0', '10'
                          ],
                          [
                              '17', '869', '25.00', '68.00', '130.00', '75.00',
                              '12', '6-3-1', '0', '10'
                          ],
                          [
                              '18', '3464', '24.00', '135.00', '80.00',
                              '109.00', '14', '5-5-0', '0', '10'
                          ],
                          [
                              '19', '3467', '24.00', '101.00', '80.00',
                              '123.00', '10', '7-3-0', '0', '10'
                          ],
                          [
                              '20', '3718', '24.00', '100.00', '60.00',
                              '106.00', '12', '6-4-0', '0', '10'
                          ],
                          [
                              '21', '3461', '24.00', '79.00', '30.00', '94.00',
                              '14', '5-5-0', '0', '10'
                          ],
                          [
                              '22', '4055', '24.00', '78.00', '80.00', '79.00',
                              '16', '4-6-0', '0', '10'
                          ],
                          [
                              '23', '1922', '23.00', '114.00', '110.00',
                              '151.00', '10', '6-3-1', '0', '10'
                          ],
                          [
                              '24', '95', '22.00', '120.00', '70.00', '123.00',
                              '14', '4-6-0', '0', '10'
                          ],
                          [
                              '25', '1991', '22.00', '113.00', '100.00',
                              '58.00', '12', '5-5-0', '0', '10'
                          ],
                          [
                              '26', '839', '22.00', '96.00', '110.00',
                              '136.00', '10', '6-4-0', '0', '10'
                          ],
                          [
                              '27', '1099', '21.00', '126.00', '110.00',
                              '97.00', '8', '6-3-1', '0', '10'
                          ],
                          [
                              '28', '230', '20.00', '143.00', '80.00',
                              '104.00', '8', '6-4-0', '0', '10'
                          ],
                          [
                              '29', '3017', '20.00', '134.00', '50.00',
                              '88.00', '12', '4-6-0', '0', '10'
                          ],
                          [
                              '30', '2067', '20.00', '128.00', '80.00',
                              '122.00', '10', '5-5-0', '0', '10'
                          ],
                          [
                              '31', '250', '20.00', '118.00', '40.00', '99.00',
                              '10', '5-5-0', '0', '10'
                          ],
                          [
                              '32', '155', '20.00', '100.00', '50.00', '74.00',
                              '12', '4-6-0', '0', '10'
                          ],
                          [
                              '33', '236', '20.00', '99.00', '20.00', '126.00',
                              '10', '5-5-0', '0', '10'
                          ],
                          [
                              '34', '1124', '20.00', '92.00', '80.00',
                              '109.00', '8', '6-4-0', '0', '10'
                          ],
                          [
                              '35', '3146', '20.00', '81.00', '110.00',
                              '81.00', '6', '7-3-0', '0', '10'
                          ],
                          [
                              '36', '663', '20.00', '71.00', '90.00', '90.00',
                              '12', '4-6-0', '0', '10'
                          ],
                          [
                              '37', '1699', '20.00', '70.00', '80.00',
                              '139.00', '12', '4-6-0', '0', '10'
                          ],
                          [
                              '38', '1027', '20.00', '53.00', '70.00', '97.00',
                              '12', '4-6-0', '0', '10'
                          ],
                          [
                              '39', '20', '19.00', '79.00', '70.00', '106.00',
                              '9', '5-5-0', '0', '10'
                          ],
                          [
                              '40', '3182', '18.00', '108.00', '60.00',
                              '147.00', '8', '5-5-0', '0', '10'
                          ],
                          [
                              '41', '229', '18.00', '97.00', '40.00', '153.00',
                              '10', '4-6-0', '0', '10'
                          ],
                          [
                              '42', '1665', '18.00', '95.00', '120.00',
                              '106.00', '10', '4-6-0', '0', '10'
                          ],
                          [
                              '43', '228', '18.00', '81.00', '60.00', '163.00',
                              '10', '4-6-0', '0', '10'
                          ],
                          [
                              '44', '178', '18.00', '81.00', '50.00', '58.00',
                              '12', '3-7-0', '0', '10'
                          ],
                          [
                              '45', '1740', '18.00', '62.00', '20.00', '99.00',
                              '8', '5-5-0', '0', '10'
                          ],
                          [
                              '46', '3634', '18.00', '54.00', '30.00',
                              '105.00', '10', '4-6-0', '0', '10'
                          ],
                          [
                              '47', '2791', '18.00', '53.00', '100.00',
                              '108.00', '10', '4-6-0', '0', '10'
                          ],
                          [
                              '48', '571', '18.00', '53.00', '70.00', '109.00',
                              '10', '4-6-0', '0', '10'
                          ],
                          [
                              '49', '2170', '17.00', '89.00', '60.00',
                              '103.00', '9', '4-5-0', '1', '10'
                          ],
                          [
                              '50', '1493', '16.00', '150.00', '60.00',
                              '132.00', '6', '5-5-0', '0', '10'
                          ],
                          [
                              '51', '549', '16.00', '129.00', '100.00',
                              '91.00', '6', '5-5-0', '0', '10'
                          ],
                          [
                              '52', '743', '16.00', '70.00', '30.00', '67.00',
                              '10', '3-7-0', '0', '10'
                          ],
                          [
                              '53', '2836', '16.00', '64.00', '80.00',
                              '126.00', '8', '4-6-0', '0', '10'
                          ],
                          [
                              '54', '999', '14.00', '114.00', '20.00', '79.00',
                              '10', '2-8-0', '0', '10'
                          ],
                          [
                              '55', '3525', '14.00', '109.00', '40.00',
                              '66.00', '6', '4-6-0', '0', '10'
                          ],
                          [
                              '56', '3104', '14.00', '92.00', '20.00', '80.00',
                              '6', '4-6-0', '0', '10'
                          ],
                          [
                              '57', '3555', '14.00', '68.00', '60.00', '68.00',
                              '8', '3-7-0', '0', '10'
                          ],
                          [
                              '58', '4134', '13.00', '96.00', '30.00', '80.00',
                              '6', '3-6-1', '0', '10'
                          ],
                          [
                              '59', '1559', '12.00', '110.00', '10.00',
                              '94.00', '8', '2-8-0', '0', '10'
                          ],
                          [
                              '60', '3719', '12.00', '97.00', '60.00', '95.00',
                              '6', '3-7-0', '0', '10'
                          ],
                          [
                              '61', '3654', '12.00', '59.00', '20.00', '57.00',
                              '8', '2-8-0', '0', '10'
                          ],
                          [
                              '62', '2785', '12.00', '41.00', '70.00', '96.00',
                              '8', '2-8-0', '0', '10'
                          ],
                          [
                              '63', '1880', '10.00', '57.00', '40.00', '86.00',
                              '6', '2-8-0', '0', '10'
                          ],
                          [
                              '64', '1784', '10.00', '44.00', '40.00', '60.00',
                              '6', '2-7-0', '1', '10'
                          ]])
        self.assertEqual(event_details.alliance_selections,
                         self.new_alliance_selections)

    def assertOldEventDetails(self, event_details):
        self.assertEqual(event_details.key.id(), "2011ct")

    def test_createOrUpdate(self):
        EventDetailsManipulator.createOrUpdate(self.old_event_details)
        self.assertOldEventDetails(EventDetails.get_by_id('2011ct'))
        EventDetailsManipulator.createOrUpdate(self.new_event_details)
        self.assertMergedEventDetails(EventDetails.get_by_id('2011ct'))

    def test_findOrSpawn(self):
        self.old_event_details.put()
        self.assertMergedEventDetails(
            EventDetailsManipulator.findOrSpawn(self.new_event_details))

    def test_updateMerge(self):
        self.assertMergedEventDetails(
            EventDetailsManipulator.updateMerge(self.new_event_details,
                                                self.old_event_details))
示例#12
0
class TestListDistrictEventsController(unittest2.TestCase):
    def setUp(self):
        app = webapp2.WSGIApplication([webapp2.Route(r'/<district_abbrev:>/<year:>', ApiDistrictEventsController, methods=['GET'])], debug=True)
        self.testapp = webtest.TestApp(app)

        self.testbed = testbed.Testbed()
        self.testbed.activate()
        self.testbed.init_datastore_v3_stub()
        self.testbed.init_urlfetch_stub()
        self.testbed.init_memcache_stub()
        ndb.get_context().clear_cache()  # Prevent data from leaking between tests

        self.testbed.init_taskqueue_stub(root_path=".")

        self.district = District(
            id='2010ne',
            year=2010,
            abbreviation='ne',
            display_name='New England',
        )
        self.district.put()

        self.event = Event(
            id="2010sc",
            name="Palmetto Regional",
            event_type_enum=EventType.DISTRICT_CMP,
            district_key=ndb.Key(District, '2010ne'),
            short_name="Palmetto",
            event_short="sc",
            year=2010,
            end_date=datetime(2010, 03, 27),
            official=True,
            city="Clemson",
            state_prov="SC",
            country="USA",
            venue="Long Beach Arena",
            venue_address="Long Beach Arena\r\n300 East Ocean Blvd\r\nLong Beach, CA 90802\r\nUSA",
            start_date=datetime(2010, 03, 24),
            webcast_json="[{\"type\": \"twitch\", \"channel\": \"frcgamesense\"}]",
            website="http://www.firstsv.org"
        )
        self.event.put()

        self.event_details = EventDetails(
            id=self.event.key.id(),
            alliance_selections=[
                {"declines": [], "picks": ["frc971", "frc254", "frc1662"]},
                {"declines": [], "picks": ["frc1678", "frc368", "frc4171"]},
                {"declines": [], "picks": ["frc2035", "frc192", "frc4990"]},
                {"declines": [], "picks": ["frc1323", "frc846", "frc2135"]},
                {"declines": [], "picks": ["frc2144", "frc1388", "frc668"]},
                {"declines": [], "picks": ["frc1280", "frc604", "frc100"]},
                {"declines": [], "picks": ["frc114", "frc852", "frc841"]},
                {"declines": [], "picks": ["frc2473", "frc3256", "frc1868"]}
            ]
        )
        self.event_details.put()

    def tearDown(self):
        self.testbed.deactivate()

    def assertDistrictEvent(self, event):
        self.assertEqual(event["key"], self.event.key_name)
        self.assertEqual(event["name"], self.event.name)
        self.assertEqual(event["short_name"], self.event.short_name)
        self.assertEqual(event["official"], self.event.official)
        self.assertEqual(event["event_type_string"], self.event.event_type_str)
        self.assertEqual(event["event_type"], self.event.event_type_enum)
        self.assertEqual(event["event_district_string"], self.event.event_district_str)
        self.assertEqual(event["event_district"], self.event.event_district_enum)
        self.assertEqual(event["start_date"], self.event.start_date.date().isoformat())
        self.assertEqual(event["end_date"], self.event.end_date.date().isoformat())
        self.assertEqual(event["location"], self.event.location)
        self.assertEqual(event["venue_address"], self.event.venue_address.replace('\r\n', '\n'))
        self.assertEqual(event["webcast"], json.loads(self.event.webcast_json))
        self.assertEqual(event["alliances"], self.event.alliance_selections)
        self.assertEqual(event["website"], self.event.website)

    def test_event_api(self):
        response = self.testapp.get("/{}/2010".format(self.district.abbreviation), headers={"X-TBA-App-Id": "tba-tests:disstrict-controller-test:v01"})

        events = json.loads(response.body)
        self.assertDistrictEvent(events[0])