def test_caption__defaults_to_title(self): session = Client().session() image = Image(title='the title', filename='') session.add(image) image.add_tags(['cat', 'awesome']) eq_(image.caption(), 'the title')
def add(request_format): tag_names = request.form['tags'].split(' ') url = request.form['url'] if url: print 'fetching from remote url' truck = ImageTruck.new_from_url(url) elif request.files['file']: image = request.files['file'] truck = ImageTruck.new_from_stream(image.stream, image.mimetype) else: abort(400) metadata = ImageMetadata.image_metadata(truck.contents) print 'potentially reorienting' truck.contents = ReorientImage.reorient_image(truck.contents) print 'uploading to s3' truck.upload() session = Client().session() image = Image(filename=truck.calculate_filename(), source_url=url, description=request.form.get('description'), title=request.form.get('title'), **metadata) album_id = request.form['album'] if album_id: image.album_id = album_id session.add(image) image.add_tags(tag_names) ResizeImage.make_resizes(image, truck) if request_format == 'html': return redirect(url_for('show_image', image_id=image.image_id)) elif request_format == 'json': return {'url': truck.url()}
def test_find_by_filename__is_case_insensitive(self): session = Client().session() session.add(Image(filename='deadbeef', source_url='example.com/foo')) session.flush() image = Image.find_by_filename('DEADBEEF') eq_(image.source_url, 'example.com/foo')
def file_type_test(self, bucket_method, test_file_name, content_type, resized_size): bucket = Mock() bucket_method.return_value = bucket new_key = Mock() bucket.new_key.return_value = new_key test_file = os.path.join(os.path.dirname(__file__), test_file_name) image_handler = ImageHandler.open(test_file) with open(test_file, 'r') as fh: truck = ImageTruck.new_from_stream(fh, content_type) session = Client().session() image = ImageTable(filename='badcafe') session.add(image) session.flush() ResizeImage._resize_image(image, image_handler, truck, 'thumbnail') new_key.set_metadata.assert_called_with('Content-Type', content_type) resized_contents = new_key.set_contents_from_string.call_args[0][0] image_handler = ImageHandler.open(StringIO.StringIO(resized_contents)) eq_(image_handler.size, resized_size)
def test_upload_an_image_with_json_format(self, ImageTruck, delay): truck = Mock() ImageTruck.new_from_url.return_value = truck truck.filename = 'CA741C' truck.url.return_value = 'cloudfrunt.nut/CA741C' truck.contents = b'' truck.content_type = "image/gif" task_id = str(uuid.uuid4()) delay.return_value = task_id response = self.app.post('/add.json', data={ 'album': '', 'url': 'imgur.com/cool_cat.gif'}) eq_(response.status_code, 200, response.data) session = Client().session() image = session.query(Image).one() body = json.loads(response.data) eq_(body, [{ 'url': 'cloudfrunt.nut/CA741C', 'image_id': image.image_id, 'task_id': task_id, }]) contents = session.query(ImageContents).one() eq_(contents.image_id, image.image_id) delay.assert_called_with([], process_image, contents.image_contents_id)
def test_add_tag_to_an_untagged_image(self): session = Client().session() pic = Image(filename="tagless", title="Untagged Picture") session.add(pic) session.flush() self.visit_url('/image/{0}'.format(pic.image_id)) tag_button = self.browser.find_by_id('tag-button') assert tag_button, "Couldn't find a button for listing tags!" tag_button.click() tag_list = self.browser.find_by_css('ul.view-tags') assert not tag_list.visible, "Popped up an empty tag dropdown!" self.browser.click_link_by_text('Edit') add_tag = self.browser.find_by_css('a.add-tag') add_tag.click() tag_input = self.browser.find_by_id('tag')[0] tag_input.fill('untagged\n') self.browser.click_link_by_text('Stop Editing') tag_button.click() tags = self.browser.find_by_css('li.tag') assert all([t.visible for t in tags]), "Tag listing was not visible!" eq_([t.text for t in tags], ['untagged'])
def _resize_image(cls, image, image_handler, truck, size): session = Client().session() (width, height) = image_handler.size (new_width, new_height) = cls._new_dimensions(width, height, RESIZES[size]) print 'resizing to %s' % size resized = image_handler.resize((new_width, new_height), ImageHandler.ANTIALIAS) (_, contents_file) = tempfile.mkstemp() try: resized.save(contents_file, image_handler.format) with open(contents_file, 'r') as contents: print 'uploading resized image' truck.upload_resize(contents.read(), size) finally: os.unlink(contents_file) resize = ImageResize(image_id=image.image_id, width=new_width, height=new_height, suffix=size) session.add(resize) session.flush()
def test_add_tag_to_an_untagged_image(self): session = Client().session() pic = Image(filename="tagless", title="Untagged Picture") session.add(pic) session.flush() self.visit_url('/image/{0}'.format(pic.image_id)) tag_button = self.browser.find_by_id('tag-button') assert tag_button, "Couldn't find a button for listing tags!" assert tag_button.has_class("disabled"), \ "Tag button enabled without tags!" self.browser.click_link_by_text('Edit') add_tag = self.browser.find_by_css('a.add-tag') add_tag.click() tag_input = self.browser.find_by_id('tag')[0] tag_input.type('untagged') tag_input.type(Keys.ENTER) self.browser.click_link_by_text('Stop Editing') tag_button.click() tags = self.browser.find_by_css('li.tag') assert all([t.visible for t in tags]), "Tag listing was not visible!" eq_([t.text for t in tags], ['untagged'])
def get_item_batch(tag_names, table_name, attributes_to_get): if not tag_names: raise StopIteration tag_names = list(set(tag_names)) unprocessed_keys = tag_names[MAX_ITEMS_TO_REQUEST:] tag_names = tag_names[:MAX_ITEMS_TO_REQUEST] dynamo = Client().get_dynamodb() table = Client().table(table_name) batch_list = BatchList(dynamo) batch_list.add_batch(table, tag_names, attributes_to_get=attributes_to_get + [HASH_KEY]) response = dynamo.batch_get_item(batch_list) items = response['Responses'][table.name]['Items'] if response['UnprocessedKeys'] \ and table.name in response['UnprocessedKeys']: for key in response['UnprocessedKeys'][table.name]['Keys']: unprocessed_keys.append(key['HashKeyElement']) for item in items: yield item for item in get_item_batch(unprocessed_keys, table_name, attributes_to_get): yield item
def test_change_album(self): session = Client().session() image = Image(filename='deadbeef') session.add(image) migrant = Album(name='migrant') pink_friday = Album(name="Pink Friday") session.add(migrant) session.add(pink_friday) session.flush() self.visit_url('/image/%d' % image.image_id) assert self.browser.is_text_present('image has no album') assert self.browser.is_text_present('set album') set_album = self.browser.find_by_css('#set-album').first set_album.click() self.browser.select('album', pink_friday.album_id) assert self.browser.is_text_present( "image appears in the album 'Pink Friday'"),\ "Album info wasn't present" del image image = session.query(Image).one() eq_(image.album_id, pink_friday.album_id) self.visit_url('/image/%d' % image.image_id) assert self.browser.is_text_present( "image appears in the album 'Pink Friday'"),\ "Album info wasn't right after reload"
def test_upload_an_image_twice(self, ImageTruck, ImageMetadata, ResizeImage): truck = Mock() ImageTruck.new_from_stream.return_value = truck truck.calculate_filename.return_value = 'CA7' truck.calculate_filename.return_value = 'CA7' truck.url.return_value = 'ess three' ImageMetadata.image_metadata.return_value = {} response = self.app.post('/add', data={ 'tags': 'pet', 'url': '', 'album': '', 'file': (StringIO(str('booya')), 'img.jpg')}) eq_(response.status_code, 302) response = self.app.post('/add', data={ 'tags': 'pet', 'url': '', 'album': '', 'file': (StringIO(str('booya')), 'img.jpg')}) eq_(response.status_code, 302) session = Client().session() image = session.query(Image).one() image_tags = session.query(ImageTag.image_id).all() eq_(image_tags, [(image.image_id,)])
def test_upload_an_image(self, ImageTruck, ResizeImage, ImageMetadata): truck = Mock() ImageTruck.new_from_stream.return_value = truck truck.calculate_filename.return_value = 'CA7' truck.url.return_value = 'ess three' ImageMetadata.image_metadata.return_value = { 'camera': 'Samsung NX210', 'photographed_at': '2013-05-09 12:00:00', 'focal_length': 30, 'aperture': '1/1.8', 'shutter_speed': 5, 'iso': '400'} response = self.app.post('/add', data={ 'album': '', 'tags': 'pet cool', 'url': '', 'title': 'My cat being awesome', 'description': 'my cat is awesome. You can see how awesome.', 'file': (StringIO(str('booya')), 'img.jpg')}) session = Client().session() image = session.query(Image).one() eq_(image.filename, 'CA7') eq_(image.source_url, '') eq_(image.title, 'My cat being awesome') eq_(image.description, 'my cat is awesome. You can see how awesome.') ResizeImage.make_resizes.assert_called_with(image, truck) eq_(response.status_code, 302, response.data) eq_(response.headers['Location'], 'http://localhost/image/%d' % image.image_id)
def test_caption__falls_back_to_tags(self): session = Client().session() image = Image(title='', filename='') session.add(image) image.add_tags(['cat', 'awesome']) eq_(image.caption(), 'awesome cat')
def coordinated_commit(queued_tasks): session = Client().session() try: session.commit() except sqlalchemy.exc.OperationalError as sqlError: # If we've sent tasks to redis but have lost the database, those tasks # probably point to invalid data. They'll likely fail anyway when the # worker can't get the database, and even if they don't, whatever # operation they relate to has been lost. exc_info = sys.exc_info() try: for task in queued_tasks: task.revoke() except (redis.exceptions.ConnectionError, redis.exceptions.TimeoutError) as redisError: # If we've lost the database, redis connection errors seem likely. # Try to report the whole failure. raise SkyIsFallingError(sqlError, redisError), None, exc_info[2] raise sqlError, None, exc_info[2] except (sqlalchemy.exc.DatabaseError, sqlalchemy.exc.StatementError) as sqlError: exc_info = sys.exc_info() try: # If we've sent tasks to redis, they probably point to invalid # data. Even if they don't, whatever operation they relate to was # invalid in some way or another, so this needs to be a # coordinated rollback. coordinated_rollback(queued_tasks) raise sqlError, None, exc_info[2] except (redis.exceptions.ConnectionError, redis.exceptions.TimeoutError) as redisError: raise SkyIsFallingError(sqlError, redisError), None, exc_info[2]
def show_add(request_format): session = Client().session() albums = session.query(Album).all() if request_format == 'html': return render_template('add.html.jinja', user=g.user, albums=albums) elif request_format == 'json': return {'albums': albums}
def file_type_test(self, bucket_method, test_file, content_type, resized_size): bucket = Mock() bucket_method.return_value = bucket new_key = Mock() bucket.new_key.return_value = new_key image_handler = ImageHandler(filename=test_file) truck = ImageTruck.new_from_file(test_file) session = Client().session() image = ImageTable(filename='badcafe') session.add(image) session.flush() after_upload = Mock() ResizeImage._resize_image(image, image_handler, truck, 'thumbnail', after_upload) new_key.set_metadata.assert_called_with('Content-Type', content_type) resized_contents = new_key.set_contents_from_string.call_args[0][0] image_handler = ImageHandler(blob=resized_contents) eq_(image_handler.size, resized_size) after_upload.assert_called_once_with('thumbnail')
def run(self, image_id, suffix=None): session = Client().session() now = time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime()) try: image = session.query(Image).\ filter((Image.created_at - timedelta(hours=1)) < now).\ filter(Image.image_id == image_id).\ one() except NoResultFound: session.rollback() logger.error('No unexpired result found for image_id {0}. ' 'Skipping.'.format(image_id)) return filename = image.filename print repr(suffix) if suffix is not None: filename = '{0}_{1}'.format(filename, suffix) config = Client().config() try: distro_id = config['aws.cloudfront_distribution_id'] Client().get_cloudfront().create_invalidation_request( distro_id, [filename]) except KeyError: pass except CloudFrontServerError as e: if e.error_code == 'TooManyInvalidationsInProgress': self.retry(exc=e) else: raise
def show_add(request_format): session = Client().session() albums = session.query(Album).all() if request_format == "html": return render_template("add.html.jinja", albums=albums) elif request_format == "json": return {"albums": albums}
def test_toomanyinvalidation_errors_cause_retry(self, MockClient): error = CloudFrontServerError(400, 'Bad Request') error.error_code = 'TooManyInvalidationsInProgress' cloudfront = Mock() cloudfront.create_invalidation_request.side_effect = error config = Client().config() client = Mock() client.config.return_value = config client.get_cloudfront.return_value = cloudfront MockClient.return_value = client session = Client().session() transaction_id = TaskTransaction.new_id() image = Image(filename='abad1dea') image.created_at = '2001-01-01 00:00:00' session.add(image) session.flush() invalidate = NeverCalledDirectlyInvalidate() invalidate.retry = Mock() invalidate(transaction_id, image.image_id) invalidate.retry.assert_called_with(exc=error)
def test_upload_an_image_twice(self, ImageTruck, delay): truck = Mock() ImageTruck.new_from_stream.return_value = truck truck.filename = 'CA7' truck.url.return_value = 'ess three' truck.contents = b'' truck.content_type = "image/jpeg" response = self.app.post('/add', data={ 'url': '', 'file': (StringIO(str('booya')), 'img.jpg')}) eq_(response.status_code, 302) response = self.app.post('/add', data={ 'url': '', 'file': (StringIO(str('booya')), 'img.jpg')}) eq_(response.status_code, 302) session = Client().session() image = session.query(Image).one() contentses = session.query(ImageContents).all() for contents in contentses: eq_(contents.image_id, image.image_id) contents_calls = [call([], process_image, x.image_contents_id) for x in contentses] delay.assert_has_calls(contents_calls)
def test_find_by_filename(self): session = Client().session() session.add(Image(filename='deadbeef', source_url='example.com/foo')) session.flush() image = Image.find_by_filename('deadbeef') eq_(image.source_url, 'example.com/foo')
def test_add_an_album(self): response = self.app.post('/new_album', data={'name': 'my pics'}) eq_(response.status_code, 302, response.data) eq_(response.headers['Location'], 'http://localhost/add') session = Client().session() albums = session.query(Album.name).all() eq_(albums, [('my pics',)])
def test_on_view_album(self): session = Client().session() album = Album(name="fotozzzz") session.add(album) session.flush() self.visit_url('/album/{0}'.format(album.album_id)) assert self.browser.is_text_present('Log out'), \ "Page didn't act like logged in"
def test_on_view_image(self): session = Client().session() image = Image(filename='bab1eface', title='face of a baby') session.add(image) session.flush() self.visit_url('/image/{0}'.format(image.image_id)) assert self.browser.is_text_present('Log out'), \ "Page didn't act like logged in"
def test_creating_with_a_new_source_url_updates_existing_record(self): session = Client().session() session.add(Image(filename='badcafe', source_url='example.com')) session.flush() session.add(Image(filename='badcafe', source_url='examp.le')) session.flush() source_url = session.query(Image.source_url).first() eq_(source_url, ('examp.le',))
def wrapper(self, transaction_id, *args, **kwargs): session = Client().session() transactions_found = session.query(TaskTransaction).\ filter(TaskTransaction.transaction_id == transaction_id).\ delete() if transactions_found == 0: raise self.retry() else: return task(self, *args, **kwargs)
def test_upload_several_images_in_one_go(self, ImageTruck, delay): (truck1, truck2, truck3) = (Mock(), Mock(), Mock()) truck1.filename = 'BAD1DEA' truck1.url.return_value = 'cloudfrunt.nut/BAD1DEA' truck1.contents = b'boom' truck1.content_type = "image/jpeg" truck2.filename = 'CAFEBABE' truck2.url.return_value = 'cloudfrunt.nut/CAFEBABE' truck2.contents = b'shaka' truck2.content_type = "image/jpeg" truck3.filename = 'DADD1E' truck3.url.return_value = 'cloudfrunt.nut/DADD1E' truck3.contents = b'laka' truck3.content_type = "image/jpeg" ImageTruck.new_from_stream.side_effect = [truck1, truck2, truck3] id1 = str(uuid.uuid4()) id2 = str(uuid.uuid4()) id3 = str(uuid.uuid4()) delay.side_effect = [id1, id2, id3] response = self.app.post('/add.json', data={ 'album': '', 'url': '', 'file[]': [ (StringIO(str('boom')), 'image_1.jpg'), (StringIO(str('shaka')), 'image_2.jpg'), (StringIO(str('laka')), 'image_3.jpg'), ]}) eq_(response.status_code, 200, response.data) session = Client().session() images = session.query(Image).all() body = json.loads(response.data) eq_(body, [ { 'url': 'cloudfrunt.nut/BAD1DEA', 'image_id': images[0].image_id, 'task_id': id1, }, { 'url': 'cloudfrunt.nut/CAFEBABE', 'image_id': images[1].image_id, 'task_id': id2, }, { 'url': 'cloudfrunt.nut/DADD1E', 'image_id': images[2].image_id, 'task_id': id3, }, ])
def test_created_at_is_set_at_creation_time(self, mock_time): now = time.strptime("2011-05-09 13:01:01", "%Y-%m-%d %H:%M:%S") mock_time.strftime = time.strftime mock_time.gmtime.return_value = now session = Client().session() album = Album(name="my pix") session.add(album) session.flush() eq_(album.created_at, "2011-05-09 13:01:01")
def get_filenames(self): from catsnap.table.image import Image from catsnap.table.image_tag import ImageTag session = Client().session() filenames = session.query(Image.filename).\ join(ImageTag).\ filter(ImageTag.image_id == Image.image_id).\ filter(ImageTag.tag_id == self.tag_id) for filename in filenames: yield filename[0]
def remove_tag(self, tag_name): from catsnap.table.image_tag import ImageTag from catsnap.table.tag import Tag session = Client().session() image_tag = session.query(ImageTag).\ join(Tag, Tag.tag_id == ImageTag.tag_id).\ filter(Tag.name == tag_name).\ filter(ImageTag.image_id == self.image_id).\ one() session.delete(image_tag)