def setUp(self):
        self.client = Client(MY_OAUTH_KEY, MY_OAUTH_SECRET, API_VERSION, API_HOST, API_PORT)
        self.known_points = {
            'darrell_k_royal_stadium': {
                'lat': 30.283863,
                'lon': -97.732519,
                'expected_response': EXPECTED_RESPONSES['darrell_k_royal_stadium']
            },
            'att_park': {
                'lat': 37.778434,
                'lon': -122.389146,
                'expected_response': EXPECTED_RESPONSES['att_park']
            },
            'invesco_field': {
                'lat': 39.744026,
                'lon': -105.019893,
                'expected_response': EXPECTED_RESPONSES['invesco_field']
            }
        }

        # Request known points.
        self.known_requests = []
        for (point_name, point) in self.known_points.iteritems():
            point['name'] = point_name
            response = self.client.get_context(point['lat'], point['lon'])
            self.known_points[point_name]['response'] = response
            self.known_requests.append((point, response))

        # Request random points.
        self.random_requests = []
        for i in range(10):
            (lat, lon) = random_lat_lon()
            point = {'lat': lat, 'lon': lon}
            response = self.client.get_context(lat, lon)
            self.random_requests.append((point, response))
class PerformanceTest(object):
    def __init__(self, number_of_requests=10000):
        self.number_of_requests = number_of_requests
        self.client = Client(MY_OAUTH_KEY, MY_OAUTH_SECRET, API_VERSION, API_HOST, API_PORT)
        print self.client
        self.responses = []

    def run(self):
        requests_completed = 0
        requests_failed = 0

        for i in range(self.number_of_requests):
            try:
                print 'Trying request %s' % i
                timed_response = self._timed_response()
                requests_completed += 1
                self.responses.append(timed_response)
            except APIError:
                requests_failed += 1
                
        print self.responses
        print '%s requests completed, %s requests failed' % (requests_completed, requests_failed)

        times = [response['time_elapsed'] for response in self.responses]
        print '\n\nmin: %s max: %s avg: %s\n\n' % (min(times), max(times), (sum(times) / len(times)))
        bins = [i * 0.1 for i in range(20)] + [2.0] + [10.0]
        histogram = numpy.histogram(times, bins=bins)
        frequencies = [frequency for frequency in histogram[0]]
        bins = [bin for bin in histogram[1]]
        for (i, bin) in enumerate(bins):
            print '%ss' % bin
            try:
                print '\t' + str(frequencies[i]) + '\t' + '=' * frequencies[i]
            except:
                pass

    def _timed_response(self):
        (lat, lon) = self._random_lat_lon()
        print 'Timing client.get_context(%s, %s)' % (lat, lon)
        start_time = time.time()
        response = self.client.get_context(lat, lon)
        time_elapsed = time.time() - start_time
        print time_elapsed
        return {'lat': lat,
                'lon': lon,
                'response': response,
                'time_elapsed': time_elapsed}

    def _random_lat_lon(self):
        return (random.uniform(-90.0, 90.0), random.uniform(-180.0, 180.0))
 def setUp(self):
     self.client = Client(MY_OAUTH_KEY, MY_OAUTH_SECRET, API_VERSION, API_HOST, API_PORT)
     self.query_lat = D('37.8016')
     self.query_lon = D('-122.4783')
class ClientTest(unittest.TestCase):
    def setUp(self):
        self.client = Client(MY_OAUTH_KEY, MY_OAUTH_SECRET, API_VERSION, API_HOST, API_PORT)
        self.query_lat = D('37.8016')
        self.query_lon = D('-122.4783')

    def _record(self):
        self.record_id += 1
        self.record_lat = (self.record_lat + 10) % 90
        self.record_lon = (self.record_lon + 10) % 180

        return Feature(
            layer=TESTING_LAYER,
            id=str(self.record_id),
            coordinates=(self.record_lat, self.record_lon)
        )

    def test_wrong_endpoint(self):
        self.assertRaises(Exception, self.client._endpoint, 'wrongwrong')

    def test_missing_argument(self):
        self.assertRaises(Exception, self.client._endpoint, 'context')

    def test_get_context(self):
        mockhttp = mock.Mock()
        mockhttp.request.return_value = ({'status': '200', 'content-type': 'application/json', }, EXAMPLE_BODY)
        self.client.http = mockhttp

        res = self.client.get_context(self.query_lat, self.query_lon)
        self.assertEqual(mockhttp.method_calls[0][0], 'request')
        self.assertEqual(mockhttp.method_calls[0][1][0], 'http://api.simplegeo.com:80/%s/context/%s,%s.json' % (API_VERSION, self.query_lat, self.query_lon))
        self.assertEqual(mockhttp.method_calls[0][1][1], 'GET')
        # the code under test is required to have json-decoded this before handing it back
        self.failUnless(isinstance(res, dict), (type(res), repr(res)))

    @mock.patch('oauth2.Request.make_timestamp')
    @mock.patch('oauth2.Request.make_nonce')
    def test_oauth(self, mock_make_nonce, mock_make_timestamp):
        mock_make_nonce.return_value = 5
        mock_make_timestamp.return_value = 6

        mockhttp = mock.Mock()
        mockhttp.request.return_value = ({'status': '200', 'content-type': 'application/json', }, EXAMPLE_BODY)
        self.client.http = mockhttp

        self.client.get_context(self.query_lat, self.query_lon)

        self.assertEqual(mockhttp.method_calls[0][2]['body'], None)
        self.assertEqual(mockhttp.method_calls[0][2]['headers']['Authorization'], 'OAuth realm="http://api.simplegeo.com", oauth_nonce="5", oauth_timestamp="6", oauth_consumer_key="MY_OAUTH_KEY", oauth_signature_method="HMAC-SHA1", oauth_version="1.0", oauth_signature="AObXFB%2BqjwC20j5guAprkiREfIg%3D"')

    def test_get_context_by_address(self):
        mockhttp = mock.Mock()
        mockhttp.request.return_value = ({'status': '200', 'content-type': 'application/json', }, EXAMPLE_BODY)
        self.client.http = mockhttp

        addr = '41 Decatur St, San Francisco, CA'
        self.client.get_context_by_address(addr)
        self.assertEqual(mockhttp.method_calls[0][0], 'request')
        self.assertEqual(mockhttp.method_calls[0][1][0], 'http://api.simplegeo.com:80/%s/context/address.json?address=%s' % (API_VERSION, urllib.quote_plus(addr)))
        self.assertEqual(mockhttp.method_calls[0][1][1], 'GET')

    def test_get_context_by_my_ip(self):
        mockhttp = mock.Mock()
        mockhttp.request.return_value = ({'status': '200', 'content-type': 'application/json', }, EXAMPLE_BODY)
        self.client.http = mockhttp

        self.client.get_context_by_my_ip()
        self.assertEqual(mockhttp.method_calls[0][0], 'request')
        self.assertEqual(mockhttp.method_calls[0][1][0], 'http://api.simplegeo.com:80/%s/context/ip.json' % (API_VERSION,))
        self.assertEqual(mockhttp.method_calls[0][1][1], 'GET')

    def test_get_context_by_ip(self):
        mockhttp = mock.Mock()
        mockhttp.request.return_value = ({'status': '200', 'content-type': 'application/json', }, EXAMPLE_BODY)
        self.client.http = mockhttp

        ipaddr = '192.0.32.10'
        self.client.get_context_by_ip(ipaddr=ipaddr)
        self.assertEqual(mockhttp.method_calls[0][0], 'request')
        self.assertEqual(mockhttp.method_calls[0][1][0], 'http://api.simplegeo.com:80/%s/context/%s.json' % (API_VERSION, ipaddr))
        self.assertEqual(mockhttp.method_calls[0][1][1], 'GET')

    def test_get_context_by_ip_invalid(self):
        mockhttp = mock.Mock()
        mockhttp.request.return_value = ({'status': '200', 'content-type': 'application/json', }, EXAMPLE_BODY)
        self.client.http = mockhttp

        self.failUnlessRaises(AssertionError, self.client.get_context_by_ip, '40.1,127.999')

    def test_get_context_invalid(self):
        mockhttp = mock.Mock()
        mockhttp.request.return_value = ({'status': '200', 'content-type': 'application/json', }, EXAMPLE_BODY)
        self.client.http = mockhttp

        self.failUnlessRaises(AssertionError, self.client.get_context, -91, 100)
        self.failUnlessRaises(AssertionError, self.client.get_context, -11, 361)

    def test_get_context_no_body(self):
        mockhttp = mock.Mock()
        mockhttp.request.return_value = ({'status': '200', 'content-type': 'application/json', }, None)
        self.client.http = mockhttp

        self.failUnlessRaises(DecodeError, self.client.get_context, self.query_lat, self.query_lon)
        self.assertEqual(mockhttp.method_calls[0][0], 'request')
        self.assertEqual(mockhttp.method_calls[0][1][0], 'http://api.simplegeo.com:80/%s/context/%s,%s.json' % (API_VERSION, self.query_lat, self.query_lon))
        self.assertEqual(mockhttp.method_calls[0][1][1], 'GET')

    def test_get_context_bad_json(self):
        mockhttp = mock.Mock()
        mockhttp.request.return_value = ({'status': '200', 'content-type': 'application/json', }, EXAMPLE_BODY + 'some crap')
        self.client.http = mockhttp

        try:
            self.client.get_context(self.query_lat, self.query_lon)
        except DecodeError, e:
            self.failUnlessEqual(e.code,None,repr(e.code))
            self.failUnless("Could not decode" in e.msg, repr(e.msg))
            repr(e)

        self.assertEqual(mockhttp.method_calls[0][0], 'request')
        self.assertEqual(mockhttp.method_calls[0][1][0], 'http://api.simplegeo.com:80/%s/context/%s,%s.json' % (API_VERSION, self.query_lat, self.query_lon))
        self.assertEqual(mockhttp.method_calls[0][1][1], 'GET')
class ConsumptionTest(unittest.TestCase):
    def setUp(self):
        self.client = Client(MY_OAUTH_KEY, MY_OAUTH_SECRET, API_VERSION, API_HOST, API_PORT)
        self.known_points = {
            'darrell_k_royal_stadium': {
                'lat': 30.283863,
                'lon': -97.732519,
                'expected_response': EXPECTED_RESPONSES['darrell_k_royal_stadium']
            },
            'att_park': {
                'lat': 37.778434,
                'lon': -122.389146,
                'expected_response': EXPECTED_RESPONSES['att_park']
            },
            'invesco_field': {
                'lat': 39.744026,
                'lon': -105.019893,
                'expected_response': EXPECTED_RESPONSES['invesco_field']
            }
        }

        # Request known points.
        self.known_requests = []
        for (point_name, point) in self.known_points.iteritems():
            point['name'] = point_name
            response = self.client.get_context(point['lat'], point['lon'])
            self.known_points[point_name]['response'] = response
            self.known_requests.append((point, response))

        # Request random points.
        self.random_requests = []
        for i in range(10):
            (lat, lon) = random_lat_lon()
            point = {'lat': lat, 'lon': lon}
            response = self.client.get_context(lat, lon)
            self.random_requests.append((point, response))

    def test_weather(self):
        # Invesco Field should have the weather data.
        point = self.known_points['invesco_field']
        response = point['response']

        self.assertTrue('weather' in response, 'Weather not contained in response for point %s,%s' % (point['lat'], point['lon']))
        self.assertTrue('temperature' in response['weather'], 'Temperature not found in weather in response for point %s,%s' % (point['lat'], point['lon']))
        self.assertEqual(response['weather']['temperature'][-1:], 'F', 'Temperature value %s does not end in F in response for %s,%s' % (response['weather']['temperature'], point['lat'], point['lon']))

    def test_demographics(self):
        # Invesco Field should have the demographic data.
        point = self.known_points['invesco_field']
        response = point['response']

        self.assertTrue('demographics' in response, 'Demographics not found in response for point %s,%s' % (point['lat'], point['lon']))
        self.assertTrue('metro_score' in response['demographics'], 'metro_score not found in demographics section for point %s,%s' % (point['lat'], point['lon']))
        self.assertTrue(0 <= int(response['demographics']['metro_score']) <= 10, 'Invalid value "%s" for metro_score in response for point %s,%s' % (response['demographics']['metro_score'], point['lat'], point['lon']))

    def test_expected_features_are_received(self):
        # Test that all features expected are received
        for (point, response) in self.known_requests:
            for expected_feature in point['expected_response']['features']:
                found_expected_feature = False
                for received_feature in response['features']:
                    if expected_feature == received_feature:
                        found_expected_feature = True
                self.assertTrue(found_expected_feature, 'Could not find expected feature in response for point %s,%s:\n%s' % (point['lat'], point['lon'], expected_feature))

    def test_received_features_are_expected(self):
        # Test that all features received are expected
        for (point, response) in self.known_requests:
            for received_feature in response['features']:
                found_received_feature = False
                for expected_feature in point['expected_response']['features']:
                    if received_feature == expected_feature:
                        found_received_feature = True
                self.assertTrue(found_received_feature, 'Could not find received feature in response for point %s,%s:\n%s' % (point['lat'], point['lon'], received_feature))

    def test_duplicate_handles(self):
        # Tests random requests and known requests.
        for (point, response) in self.known_requests + self.random_requests:
            for (i, feature) in enumerate(response['features']):
                for (j, possible_duplicate_feature) in enumerate(response['features']):
                    if i != j:
                        self.assertNotEqual(feature['handle'], possible_duplicate_feature['handle'], 'Found duplicate handle %s for point %s,%s' % (feature['handle'], point['lat'], point['lon']))
                        # Test for dupes in the first 25 characters of the 
                        self.assertNotEqual(feature['handle'][:25], possible_duplicate_feature['handle'][:25], 'Found duplicate *base* handle %s for point %s,%s' % (feature['handle'][:25], point['lat'], point['lon']))

    def test_duplicate_categories(self):
        # Ensure that we don't have multiple features with specified type/category/subcategory configurations.
        dupe_classifiers = [{'type': 'Region',
                             'category': 'Subnational',
                              'subcategory': 'State'},
                             {'type': 'Region',
                              'category': 'Time Zone',
                              'subcategory': ''},
                             {'type': 'Region',
                              'category': 'National',
                              'subcategory': ''},
                             {'type': 'Region',
                              'category': 'Urban Area',
                              'subcategory': ''},
                             {'type': 'Region',
                              'category': 'US Census',
                              'subcategory': 'Tract'},
                             {'type': 'Region',
                              'category': 'Neighborhood',
                              'subcategory': ''},
                             {'type': 'Region',
                              'category': 'Administrative',
                              'subcategory': 'County'},
                             {'type': 'Region',
                              'category': 'Municiple',
                              'subcategory': 'City'},
                             {'type': 'Region',
                              'category': 'School District',
                              'subcategory': 'Unified'}]
        for (point, response) in self.known_requests:
            for dupe_classifier in dupe_classifiers:
                instances_found = 0
                for feature in response['features']:
                    for classifier in feature['classifiers']:
                        if 'type' in classifier and 'category' in classifier and 'subcategory' in classifier:
                            if dupe_classifier['type'] == classifier['type'] and dupe_classifier['category'] == classifier['category'] and dupe_classifier['subcategory'] == classifier['subcategory']:
                                instances_found += 1
                                self.assertTrue(instances_found <= 1, 'Found dupe for type/categories %s/%s/%s for point %s,%s' % (dupe['type'], dupe['category'], dupe['subcategory'], point['lat'], point['lon']))
 def __init__(self, number_of_requests=10000):
     self.number_of_requests = number_of_requests
     self.client = Client(MY_OAUTH_KEY, MY_OAUTH_SECRET, API_VERSION, API_HOST, API_PORT)
     print self.client
     self.responses = []