def post(self): cache = RedisCacheFactory().create(name=app.config.get('REDIS_CACHE_NAME'), redis_host=app.config.get('REDIS_HOST')) post_data = request.get_json() url_str = post_data.get('url') custom_str = post_data.get('custom') auth_header = request.headers.get('Authorization') user_id = get_user_id(auth_header) if user_id is None: return response(message='Invalid credentials!', status=HTTPStatus.UNAUTHORIZED) crud = URLCrud(SequentialEncoder()) try: url, representation = crud.create_url(user_id, url_str, custom_str) except ValueError: return response(status=HTTPStatus.BAD_REQUEST, message='url is not formatted correctly!') cache[representation] = url.id, url_str return response( data={ 'id': url.id, 'original_url': url_str, 'short_uri': f'r/{representation}' }, message='URL shortened successfully!', status=HTTPStatus.CREATED )
class TestAuthViews(TestCase): def create_app(self): self.app = create_app(TestConfig) self.app_context = self.app.app_context() self.app_context.push() URLLog.query.delete() URL.query.delete() User.query.delete() db.create_all() self.user = UserCRUD(SimpleUserFactory()).create_user( '*****@*****.**', '12341234') self.crud = URLCrud(SequentialEncoder()) submit_url_log.delay = submit_url_log return self.app def setUp(self) -> None: response = self.client.post('/auth/login', json={ 'email': '*****@*****.**', 'password': '******' }) self.token = response.json['data']['auth_token'] def test_url_shortener_get_redirects_to_correct_link(self): url, representation = self.crud.create_url(self.user.id, 'https://foo.bar.com') response = self.client.get(f'/r/{representation}') self.assertEqual(301, response.status_code) self.assertEqual(response.headers['Location'], 'https://foo.bar.com') def test_url_shortener_create_url_log_correctly(self): url, representation = self.crud.create_url(self.user.id, 'https://foo.bar.com') response = self.client.get( f'/r/{representation}', headers={ 'User-Agent': 'Mozilla/5.0 (Linux; Android 7.0; SM-G892A Build/NRD90M; wv)' 'AppleWebKit/537.36 (KHTML, like Gecko)' 'Version/4.0 Chrome/60.0.3112.107 Mobile Safari/537.36' }) url_log: URLLog = URLLog.query.filter( URLLog.url_id == url.id).one_or_none() self.assertEqual(url.id, url_log.url_id) self.assertEqual('Chrome', url_log.browser) self.assertEqual('Linux', url_log.os) self.assertEqual('Android', url_log.platform) def test_url_shortener_get_returns_404_for_unavailable__or_invalid_url( self): response = self.client.get('/r/unavailable') self.assertEqual(404, response.status_code) response = self.client.get('/r/in.vali.d') self.assertEqual(404, response.status_code) def test_url_shortener_post_returns_401_for_unauthorized_users(self): response = self.client.post('/urls', json={'url': 'https://foo.com'}) self.assertEqual(401, response.status_code) def test_url_shortener_post_returns_401_for_bad_token(self): response = self.client.post( '/urls', json={'url': 'bad.url'}, headers={'Authorization': f'Bearer BADTOKEN'}) self.assertEqual(401, response.status_code) def test_url_shortener_post_returns_400_for_bad_urls(self): response = self.client.post( '/urls', json={'url': 'bad.url'}, headers={'Authorization': f'Bearer {self.token}'}) self.assertEqual(400, response.status_code) def test_url_shortener_works_correctly_given_token_and_correct_url(self): response = self.client.post( '/urls', json={'url': 'https://foo.bar.com?var=3&another_var=2'}, headers={'Authorization': f'Bearer {self.token}'}) self.assertEqual('https://foo.bar.com?var=3&another_var=2', response.json['data']['original_url']) self.assertTrue('short_uri' in response.json['data']) short_uri = response.json['data']['short_uri'] response = self.client.get(f'{short_uri}') self.assertEqual(301, response.status_code) self.assertEqual(response.headers['Location'], 'https://foo.bar.com?var=3&another_var=2') def test_url_shortener_uses_cache_if_exists(self): short_uri = self.client.post( '/urls', json={ 'url': 'https://foo.bar.com?var=3&another_var=2' }, headers={ 'Authorization': f'Bearer {self.token}' }).json['data']['short_uri'] url = URL.query.one_or_none() url.url = 'something_different' db.session.commit() response = self.client.get(f'{short_uri}') self.assertEqual(301, response.status_code) self.assertEqual(response.headers['Location'], 'https://foo.bar.com?var=3&another_var=2')
class TestUserCRUD(TestCase): def setUp(self): self.app = create_app(TestConfig) self.app_context = self.app.app_context() self.app_context.push() db.create_all() URLLog.query.delete() URL.query.delete() User.query.delete() self.user = UserCRUD(SimpleUserFactory()).create_user('*****@*****.**', '12341234') self.crud = URLCrud(SequentialEncoder()) def test_create_url_raises_error_for_incorrectly_formatted_url(self): self.assertRaises(ValueError, self.crud.create_url, self.user.id, 'foobar') self.assertRaises(ValueError, self.crud.create_url, self.user.id, 'foo.bar.com') def test_create_url_generates_different_representation_for_the_same_url_each_time(self): _, representation_1 = self.crud.create_url(self.user.id, 'http://foo.bar.com') _, representation_2 = self.crud.create_url(self.user.id, 'http://foo.bar.com') self.assertNotEqual(representation_1, representation_2) def test_create_url_uses_custom_representation_if_not_already_used(self): _, representation = self.crud.create_url(self.user.id, 'http://foo.bar.com', custom_representation='custom') self.assertEqual('custom', representation) def test_create_url_uses_similar_custom_representation_in_case_of_conflict_in_order(self): _, representation_1 = self.crud.create_url(self.user.id, 'http://foo.bar.com', custom_representation='custom') for i in range(10): _, representation_i = self.crud.create_url(self.user.id, 'http://foo.bar.com', custom_representation='custom') self.assertEqual(representation_i, f'custom{i}') _, representation_00 = self.crud.create_url(self.user.id, 'http://foo.bar.com', custom_representation='custom') self.assertEqual('custom00', representation_00) def test_create_url_uses_similar_custom_representation_in_case_of_conflict_without_order(self): self.crud.create_url(self.user.id, 'http://foo.bar.com', custom_representation='custom') self.crud.create_url(self.user.id, 'http://foo.bar.com', custom_representation='custom0') self.crud.create_url(self.user.id, 'http://foo.bar.com', custom_representation='custom2') _, representation = self.crud.create_url(self.user.id, 'http://foo.bar.com', custom_representation='custom') self.assertEqual('custom1', representation) def test_create_url_raises_value_error_given_invalid_custom_string(self): self.assertRaises(ValueError, self.crud.create_url, self.user.id, 'http://foo.bar.com', '!nv^l!d') def test_retrieve_url_finds_the_correct_url_given_short_representation(self): url_normal, representation_normal = self.crud.create_url(self.user.id, 'http://foo.bar.com') url_custom, representation_custom = self.crud.create_url(self.user.id, 'http://foo.bar.com', custom_representation='custom') retrieved_url_normal = self.crud.retrieve_url(representation_normal) retrieved_url_custom = self.crud.retrieve_url(representation_custom) self.assertEqual(url_normal, retrieved_url_normal) self.assertEqual(url_custom, retrieved_url_custom) def test_retrieve_url_returns_none_given_unavailable_representation(self): retrieved_url_unavailable = self.crud.retrieve_url('unavailable') self.assertIsNone(retrieved_url_unavailable) def test_retrieve_url_returns_none_given_invalid_representation(self): retrieved_url_invalid = self.crud.retrieve_url('!nv^lID') self.assertIsNone(retrieved_url_invalid) def tearDown(self) -> None: URL.query.delete() User.query.delete()