예제 #1
0
    def testPostIdConstruction(self):
        """Verify round-trip of various post-ids."""
        def _RoundTripPostId(original_episode_id, original_photo_id):
            post_id = Post.ConstructPostId(original_episode_id,
                                           original_photo_id)
            new_episode_id, new_photo_id = Post.DeconstructPostId(post_id)
            self.assertEqual(original_episode_id, new_episode_id)
            self.assertEqual(original_photo_id, new_photo_id)

        _RoundTripPostId(Episode.ConstructEpisodeId(time.time(), 0, 0),
                         Photo.ConstructPhotoId(time.time(), 0, 0))

        _RoundTripPostId(
            Episode.ConstructEpisodeId(time.time(), 1, (127, 'extra')),
            Photo.ConstructPhotoId(time.time(), 1, (127, 'extra')))

        _RoundTripPostId(
            Episode.ConstructEpisodeId(time.time(), 1, (128, None)),
            Photo.ConstructPhotoId(time.time(), 1, (128, None)))

        _RoundTripPostId(
            Episode.ConstructEpisodeId(time.time(), 4000000000,
                                       (5000000000, 'v123')),
            Photo.ConstructPhotoId(time.time(), 6000000000,
                                   (7000000000, 'v123')))
예제 #2
0
  def _CreateEpisodeWithPosts(self, sharer_user, parent_ep_id, ph_dicts):
    """Creates a new episode containing the given photos."""
    # Create the episode.
    episode_id = Episode.ConstructEpisodeId(self._op.timestamp, self._new_user.webapp_dev_id, self._unique_id)
    self._unique_id += 1
    episode = yield gen.Task(Episode.CreateNew,
                             self._client,
                             episode_id=episode_id,
                             parent_ep_id=parent_ep_id,
                             user_id=sharer_user.user_id,
                             viewpoint_id=self._viewpoint_id,
                             publish_timestamp=util.GetCurrentTimestamp(),
                             timestamp=self._op.timestamp,
                             location=ph_dicts[0].get('location', None),
                             placemark=ph_dicts[0].get('placemark', None))

    # Create the photos from photo dicts.
    photo_ids = [ph_dict['photo_id'] for ph_dict in ph_dicts]
    for photo_id in photo_ids:
      yield gen.Task(Post.CreateNew, self._client, episode_id=episode_id, photo_id=photo_id)

    # Update accounting, but only apply to the new user, since system users will remove
    # themselves from the viewpoint.
    yield self._acc_accum.SharePhotos(self._client,
                                      sharer_user.user_id,
                                      self._viewpoint_id,
                                      photo_ids,
                                      [self._new_user.user_id])

    # Update viewpoint shared by total for the sharing user.
    self._acc_accum.GetViewpointSharedBy(self._viewpoint_id, sharer_user.user_id).IncrementFromPhotoDicts(ph_dicts)

    raise gen.Return(episode)
예제 #3
0
    def testBatchQuery(self):
        """Test DBObject.BatchQuery."""
        # Create some data to query.
        keys = []
        for i in xrange(3):
            photo_id = Photo.ConstructPhotoId(time.time(),
                                              self._mobile_dev.device_id, 1)
            episode_id = Episode.ConstructEpisodeId(time.time(),
                                                    self._mobile_dev.device_id,
                                                    1)
            ph_dict = {
                'photo_id': photo_id,
                'user_id': self._user.user_id,
                'episode_id': episode_id
            }
            self._RunAsync(Photo.CreateNew, self._client, **ph_dict)
            keys.append(DBKey(photo_id, None))

        # Add a key that will not be found.
        keys.append(DBKey('unk-photo', None))

        photos = self._RunAsync(Photo.BatchQuery,
                                self._client,
                                keys,
                                None,
                                must_exist=False)
        self.assertEqual(len(photos), 4)
        for i in xrange(3):
            self.assertEqual(photos[i].GetKey(), keys[i])
        self.assertIsNone(photos[3])
예제 #4
0
def _SetWelcomeIds(user, upload_request):
    """Assigns activity, episode, and photo ids for all welcome conversation requests. Assets
  are assigned unique ids starting at 1.
  """
    # Construct the activity id.
    unique_id = 1
    act_dict = upload_request['activity']
    act_dict['activity_id'] = Activity.ConstructActivityId(
        act_dict['timestamp'], user.webapp_dev_id, unique_id)
    unique_id += 1

    # Construct the episode id.
    ep_dict = upload_request['episode']
    ep_dict['episode_id'] = Episode.ConstructEpisodeId(ep_dict['timestamp'],
                                                       user.webapp_dev_id,
                                                       unique_id)
    unique_id += 1

    # Construct the photo ids.
    for ph_dict in upload_request['photos']:
        # Create metadata for each photo.
        ph_dict['photo_id'] = Photo.ConstructPhotoId(ph_dict['timestamp'],
                                                     user.webapp_dev_id,
                                                     unique_id)
        unique_id += 1
예제 #5
0
    def testCreateAndUpdate(self):
        """Creates a episode with id pre-allocated on mobile device. Then updates the episode."""
        with EnterOpContext(Operation(1, 'o1')):
            timestamp = time.time()
            episode_id = Episode.ConstructEpisodeId(timestamp,
                                                    self._mobile_dev.device_id,
                                                    15)
            ep_dict = {
                'user_id': self._user.user_id,
                'episode_id': episode_id,
                'viewpoint_id': self._user.private_vp_id,
                'timestamp': time.time(),
                'publish_timestamp': time.time(),
                'description': 'yada yada this is a episode',
                'title': 'Episode #1'
            }

            episode = self._RunAsync(Episode.CreateNew, self._client,
                                     **ep_dict)
            episode._version = None
            self.assertEqual(ep_dict, episode._asdict())

            update_dict = {
                'episode_id': episode.episode_id,
                'user_id': episode.user_id,
                'description': 'updated description',
                'title': 'Episode #1a'
            }
            self._RunAsync(episode.UpdateExisting, self._client, **update_dict)
            episode._version = None
            ep_dict.update(update_dict)
            self.assertEqual(ep_dict, episode._asdict())
예제 #6
0
  def _UploadEpisodeWithPhoto(self):
    """Create episode with photo and upload.
    Returns: photo_id of created photo.
    """
    timestamp = time.time()

    episode_id = Episode.ConstructEpisodeId(timestamp, self._device_ids[0], 100)
    ep_dict = {'episode_id': episode_id,
               'timestamp': timestamp,
               'title': 'Episode Title'}

    photo_id = Photo.ConstructPhotoId(timestamp, self._device_ids[0], 100)
    ph_dict = {'aspect_ratio': 1.3333,
               'timestamp': timestamp,
               'tn_md5': util.ComputeMD5Hex('thumbnail image data'),
               'med_md5': util.ComputeMD5Hex('medium image data'),
               'full_md5': util.ComputeMD5Hex('full image data'),
               'orig_md5': util.ComputeMD5Hex('original image data'),
               'tn_size': 5*1024,
               'med_size': 10*1024,
               'full_size': 150*1024,
               'orig_size': 1200*1024,
               'caption': 'a photo',
               'photo_id': photo_id}

    self._tester.UploadEpisode(self._cookie, ep_dict, [ph_dict])

    return photo_id
예제 #7
0
    def testSaveDuplicateIds(self):
        """Save duplicate episode and photo ids."""
        # ------------------------------
        # Duplicate photo ids.
        # ------------------------------
        self._tester.SavePhotos(
            self._cookie,
            [(self._existing_ep_id, self._photo_ids + self._photo_ids)])
        self.assertEqual(
            self._CountEpisodes(self._cookie, self._user.private_vp_id), 3)

        # ------------------------------
        # Duplicate episode ids.
        # ------------------------------
        self._tester.SavePhotos(self._cookie,
                                [(self._existing_ep_id, self._photo_ids),
                                 (self._existing_ep_id, self._photo_ids)])
        self.assertEqual(
            self._CountEpisodes(self._cookie, self._user.private_vp_id), 5)

        # ------------------------------
        # Save same episode to same target episode multiple times.
        # ------------------------------
        new_episode_id = Episode.ConstructEpisodeId(time.time(),
                                                    self._device_ids[0],
                                                    self._test_id)
        self._test_id += 1
        self._tester.SavePhotos(self._cookie, [{
            'existing_episode_id': self._existing_ep_id,
            'new_episode_id': new_episode_id,
            'photo_ids': self._photo_ids[:1]
        }, {
            'existing_episode_id': self._existing_ep_id,
            'new_episode_id': new_episode_id,
            'photo_ids': self._photo_ids
        }])
        self.assertEqual(
            self._CountEpisodes(self._cookie, self._user.private_vp_id), 6)

        # ------------------------------
        # Duplicate viewpoint ids.
        # ------------------------------
        vp_id, ep_ids = self._tester.ShareNew(
            self._cookie, [(self._episode_id2, self._photo_ids2)],
            [self._user3.user_id], **self._CreateViewpointDict(self._cookie))

        self._tester.SavePhotos(self._cookie,
                                ep_save_list=[
                                    (self._existing_ep_id, self._photo_ids),
                                    (self._existing_ep_id, self._photo_ids)
                                ],
                                viewpoint_ids=[vp_id, vp_id])
        self.assertEqual(
            self._CountEpisodes(self._cookie, self._user.private_vp_id), 9)
예제 #8
0
 def _CreateEpisodeDict(self, user_cookie, **update_ep_dict):
   """Create dict() for a test episode, overriding default values with
   whatever is passed in "update_ep_dict"."""
   user_id, device_id = self._tester.GetIdsFromCookie(user_cookie)
   timestamp = time.time() - self._test_id
   ep_dict = {'episode_id': Episode.ConstructEpisodeId(timestamp, device_id, self._test_id),
              'timestamp': timestamp,
              'title': 'Title %s' % self._test_id,
              'description': 'Description %s. 朋友你好.' % self._test_id}
   self._test_id += 1
   ep_dict.update(**update_ep_dict)
   return ep_dict
예제 #9
0
 def testSaveDuplicatePhotos(self):
     """Save same photos from same source episode to same target episode in default viewpoint."""
     new_episode_id = Episode.ConstructEpisodeId(time.time(),
                                                 self._device_ids[0],
                                                 self._test_id)
     self._test_id += 1
     share_list = [{
         'existing_episode_id': self._existing_ep_id,
         'new_episode_id': new_episode_id,
         'photo_ids': self._photo_ids
     }]
     self._tester.SavePhotos(self._cookie, share_list)
     self._tester.SavePhotos(self._cookie, share_list)
예제 #10
0
  def testSuppressCopyTimestamp(self):
    """Test migrator that removes timestamp from share and save operations."""
    self._CreateSimpleTestAssets()

    # First do a share_new.
    new_episode_id = Episode.ConstructEpisodeId(time.time(), self._device_ids[0], self._test_id)
    self._test_id += 1

    request_dict = {'activity': self._tester.CreateActivityDict(self._cookie),
                    'viewpoint': self._CreateViewpointDict(self._cookie),
                    'episodes': [{'existing_episode_id': self._episode_id,
                                  'new_episode_id': new_episode_id,
                                  'timestamp': time.time(),
                                  'photo_ids': self._photo_ids}],
                    'contacts': self._tester.CreateContactDicts([self._user2.user_id])}
    self._SendRequest('share_new', self._cookie, request_dict, version=Message.SUPPORT_REMOVED_FOLLOWERS)

    # Now, do a share_existing.
    new_episode_id2 = Episode.ConstructEpisodeId(time.time(), self._device_ids[0], self._test_id)
    self._test_id += 1

    request_dict = {'activity': self._tester.CreateActivityDict(self._cookie),
                    'viewpoint_id': request_dict['viewpoint']['viewpoint_id'],
                    'episodes': [{'existing_episode_id': self._episode_id2,
                                  'new_episode_id': new_episode_id2,
                                  'timestamp': time.time(),
                                  'photo_ids': self._photo_ids2}]}
    self._SendRequest('share_existing', self._cookie, request_dict, version=Message.SUPPORT_REMOVED_FOLLOWERS)

    # Now, do a save_photos.
    save_episode_id = Episode.ConstructEpisodeId(time.time(), self._device_ids[1], self._test_id)
    self._test_id += 1

    request_dict = {'activity': self._tester.CreateActivityDict(self._cookie2),
                    'episodes': [{'existing_episode_id': new_episode_id,
                                  'new_episode_id': save_episode_id,
                                  'timestamp': time.time(),
                                  'photo_ids': self._photo_ids}]}
    self._SendRequest('save_photos', self._cookie2, request_dict, version=Message.SUPPORT_REMOVED_FOLLOWERS)
예제 #11
0
 def testShareSamePhotoSameEpisode(self):
     """ERROR: Try to share the same photo multiple times to same episode."""
     timestamp = time.time()
     new_episode_id = Episode.ConstructEpisodeId(timestamp,
                                                 self._device_ids[0],
                                                 self._test_id)
     self._test_id += 1
     share_dict = {
         'existing_episode_id': self._episode_id,
         'new_episode_id': new_episode_id,
         'timestamp': timestamp,
         'photo_ids': self._photo_ids
     }
     self.assertRaisesHttpError(400, self._tester.ShareNew, self._cookie,
                                [share_dict, share_dict], [])
예제 #12
0
 def testWrongViewpoint(self):
     """ERROR: Try to share photos to existing episode that is not in the target viewpoint."""
     timestamp = time.time()
     new_episode_id = Episode.ConstructEpisodeId(timestamp,
                                                 self._device_ids[0],
                                                 self._test_id)
     self._test_id += 1
     share_dict = {
         'existing_episode_id': self._episode_id,
         'new_episode_id': self._episode_id2,
         'photo_ids': self._photo_ids
     }
     self.assertRaisesHttpError(400, self._tester.ShareExisting,
                                self._cookie, self._existing_vp_id,
                                [share_dict])
예제 #13
0
    def testWrongDeviceIds(self):
        """ERROR: Try to create an episode and photo using device ids that
    are different than the ones in the user cookies.
    """
        bad_episode_id = Episode.ConstructEpisodeId(100, 1000, 1)
        self.assertRaisesHttpError(403,
                                   self._tester.UploadEpisode,
                                   self._cookie,
                                   ep_dict={
                                       'episode_id': bad_episode_id,
                                       'timestamp': 100
                                   },
                                   ph_dict_list=[])

        episode_id = Episode.ConstructEpisodeId(100, self._device_ids[0], 100)
        bad_photo_id = Photo.ConstructPhotoId(100, 1000, 1)
        self.assertRaisesHttpError(403,
                                   self._tester.UploadEpisode,
                                   self._cookie,
                                   ep_dict={},
                                   ph_dict_list=[
                                       self._CreatePhotoDict(
                                           self._cookie, photo_id=bad_photo_id)
                                   ])
예제 #14
0
    def _AllocateTargetEpisodeIds(self, client, user_id, device_id,
                                  target_viewpoint_id, source_ep_ids):
        """For each episode listed in "source_ep_ids", determines if a child episode already
    exists in the given viewpoint. If not, allocates a new episode id using the user's asset
    id allocator. The same timestamp used to create the source episode id is used to create
    the target episode id.

    Returns the list of target episodes ids, including both existing ids and allocated ids.
    """
        # First check whether each episode has already been shared/saved into the target viewpoint.
        tasks = []
        for source_ep_id in source_ep_ids:
            query_expr = ('episode.parent_ep_id={id}', {'id': source_ep_id})
            tasks.append(gen.Task(Episode.IndexQuery, client, query_expr,
                                  None))

        target_ep_ids = []
        allocate_ids_count = 0
        target_episodes_list = yield tasks
        for target_episodes in target_episodes_list:
            found_match = False
            for episode in target_episodes:
                if episode.viewpoint_id == target_viewpoint_id:
                    target_ep_ids.append(episode.episode_id)
                    found_match = True
                    break

            # If no matching child episode, then need to allocate an episode id.
            if not found_match:
                target_ep_ids.append(None)
                allocate_ids_count += 1

        if allocate_ids_count > 0:
            # Allocate ids for any episodes which do not yet exist, and merge them into target_ep_ids.
            id = yield gen.Task(User.AllocateAssetIds, client, user_id,
                                allocate_ids_count)
            for i, source_ep_id in enumerate(source_ep_ids):
                if target_ep_ids[i] is None:
                    timestamp, _, _ = source_ep_id = Episode.DeconstructEpisodeId(
                        source_ep_id)
                    target_ep_ids[i] = Episode.ConstructEpisodeId(
                        timestamp, device_id, id)
                    id += 1

        raise gen.Return(target_ep_ids)
예제 #15
0
 def _UploadPhotoOperation(self,
                           user_id,
                           device_id,
                           seed,
                           callback,
                           photo_id=None):
     """Creates an upload photos operation using seed to create unique ids."""
     request = {
         'user_id':
         user_id,
         'activity': {
             'activity_id':
             Activity.ConstructActivityId(time.time(), device_id, seed),
             'timestamp':
             time.time()
         },
         'episode': {
             'user_id':
             user_id,
             'episode_id':
             Episode.ConstructEpisodeId(time.time(), device_id, seed),
             'timestamp':
             time.time()
         },
         'photos': [{
             'photo_id':
             Photo.ConstructPhotoId(time.time(), device_id, seed)
             if photo_id is None else photo_id,
             'aspect_ratio':
             1.3333,
             'timestamp':
             time.time(),
             'tn_size':
             5 * 1024,
             'med_size':
             50 * 1024,
             'full_size':
             150 * 1024,
             'orig_size':
             1200 * 1024
         }]
     }
     Operation.CreateAndExecute(self._client, user_id, device_id,
                                'UploadEpisodeOperation.Execute', request,
                                callback)
예제 #16
0
    def testMultipleEpisodeUnshare(self):
        """Unshare photos from multiple episodes inside the same viewpoint."""
        vp_id, ep_ids = self._tester.ShareNew(
            self._cookie, [(self._new_ep_id, self._photo_ids)],
            [self._user2.user_id])
        timestamp = time.time()

        episode_id = Episode.ConstructEpisodeId(timestamp, self._device_ids[0],
                                                100)

        ep_id, ph_ids = self._tester.UploadEpisode(
            self._cookie, {}, [self._CreatePhotoDict(self._cookie)])
        new_ep_ids = self._tester.ShareExisting(self._cookie, vp_id,
                                                [(ep_id, ph_ids)])

        self._tester.Unshare(self._cookie, vp_id,
                             [(ep_ids[0], self._photo_ids),
                              (new_ep_ids[0], ph_ids)])
예제 #17
0
    def testSaveToSameEpisode(self):
        """Save multiple photos to same target episode in default viewpoint."""
        timestamp = time.time()
        new_episode_id = Episode.ConstructEpisodeId(timestamp,
                                                    self._device_ids[0],
                                                    self._test_id)
        self._test_id += 1
        share_dict1 = {
            'existing_episode_id': self._existing_ep_id,
            'new_episode_id': new_episode_id,
            'photo_ids': self._photo_ids[:1]
        }
        share_dict2 = {
            'existing_episode_id': self._existing_ep_id,
            'new_episode_id': new_episode_id,
            'photo_ids': self._photo_ids[1:]
        }

        self._tester.SavePhotos(self._cookie, [share_dict1, share_dict2])
예제 #18
0
  def testFileSizeExtraction(self):
    """Ensure that the EXTRACT_FILE_SIZES migration works correctly."""
    episode_id = Episode.ConstructEpisodeId(1, self._device_ids[0], 1)
    photo_id = Photo.ConstructPhotoId(1, self._device_ids[0], 1)
    # create request with size fields in client_data.
    request = {'activity': self._tester.CreateActivityDict(self._cookie),
               'episode': {'episode_id': episode_id,
                           'timestamp': 1},
               'photos': [self._CreatePhotoDict(self._cookie, photo_id=photo_id,
                                                client_data={'tn_size':'5', 'med_size':'40',
                                                             'full_size':'150', 'orig_size':'1200'})]}

    # remove size fields from the photo metadata, leaving only those in client_data.
    photo = request['photos'][0]
    del photo['tn_size']
    del photo['med_size']
    del photo['full_size']
    del photo['orig_size']

    self._SendRequest('upload_episode', self._cookie, request, version=Message.INLINE_INVALIDATIONS)
예제 #19
0
    def testSaveToSameEpisode(self):
        """ERROR: Try to save from two source episodes to the same target episode."""
        share_ep_ids = self._tester.ShareExisting(
            self._cookie, self._existing_vp_id,
            [(self._episode_id2, self._photo_ids2)])

        new_episode_id = Episode.ConstructEpisodeId(time.time(),
                                                    self._device_ids[0],
                                                    self._test_id)
        self._test_id += 1
        self.assertRaisesHttpError(
            400, self._tester.SavePhotos, self._cookie,
            [{
                'existing_episode_id': self._existing_ep_id,
                'new_episode_id': new_episode_id,
                'photo_ids': self._photo_ids
            }, {
                'existing_episode_id': share_ep_ids[0],
                'new_episode_id': new_episode_id,
                'photo_ids': self._photo_ids2
            }])
예제 #20
0
    def testQuery(self):
        """Verify photo creation and query by photo id."""
        def _OnQuery(p, p2):
            self.assertEqual(p2.caption, p.caption)
            self.assertEqual(p2.photo_id, p.photo_id)
            self.stop()

        def _OnCreatePhoto(p):
            Photo.Query(self._client, p.photo_id, None, partial(_OnQuery, p))

        photo_id = Photo.ConstructPhotoId(time.time(),
                                          self._mobile_dev.device_id, 1)
        episode_id = Episode.ConstructEpisodeId(time.time(),
                                                self._mobile_dev.device_id, 2)
        p_dict = {
            'photo_id': photo_id,
            'episode_id': episode_id,
            'user_id': self._user.user_id,
            'caption': 'a photo'
        }
        Photo.CreateNew(self._client, callback=_OnCreatePhoto, **p_dict)
예제 #21
0
  def testInlineInvalidationsMigration(self):
    """Ensure that the INLINE_INVALIDATIONS migration works correctly."""
    episode_id = Episode.ConstructEpisodeId(1, self._device_ids[0], 1)
    photo_id = Photo.ConstructPhotoId(1, self._device_ids[0], 1)
    request = {'activity': self._tester.CreateActivityDict(self._cookie),
               'episode': {'episode_id': episode_id,
                           'timestamp': 1},
               'photos': [self._CreatePhotoDict(self._cookie, photo_id=photo_id)]}
    self._SendRequest('upload_episode', self._cookie, request,
                      version=Message.EXTRACT_MD5_HASHES)

    request = {'episodes': [{'episode_id': episode_id,
                             'photo_ids': [photo_id]}]}
    self._SendRequest('remove_photos', self._cookie, request,
                      version=Message.EXTRACT_MD5_HASHES)

    request = {'activity': self._tester.CreateActivityDict(self._cookie),
               'viewpoint_id': self._user.private_vp_id,
               'viewed_seq': 2}
    self._SendRequest('update_viewpoint', self._cookie, request,
                      version=Message.EXTRACT_MD5_HASHES)

    response = self._SendRequest('query_notifications', self._cookie, {},
                                 version=Message.EXTRACT_MD5_HASHES)

    # upload_episode notification.
    notify_dict = response['notifications'][1]
    self.assertFalse('inline' in notify_dict)
    self.assertTrue('activity' in notify_dict)
    self.assertEqual(notify_dict['activity']['update_seq'], 1)

    # remove_photos notification.
    notify_dict = response['notifications'][2]
    self.assertFalse('inline' in notify_dict)
    self.assertFalse('activity' in notify_dict)

    # update_viewpoint notification.
    notify_dict = response['notifications'][3]
    self.assertFalse('inline' in notify_dict)
    self.assertFalse('activity' in notify_dict)
예제 #22
0
  def testUpdateEpisode(self):
    """Creates a new episode and photo and updates both."""
    timestamp = time.time()

    episode_id = Episode.ConstructEpisodeId(timestamp, self._device_ids[0], 100)
    ep_dict = {'episode_id': episode_id,
               'timestamp': timestamp,
               'title': 'Episode Title'}

    photo_id = Photo.ConstructPhotoId(timestamp, self._device_ids[0], 100)
    ph_dict = {'aspect_ratio': 1.3333,
               'timestamp': time.time(),
               'tn_md5': util.ComputeMD5Hex('thumbnail image data'),
               'med_md5': util.ComputeMD5Hex('medium image data'),
               'full_md5': util.ComputeMD5Hex('full image data'),
               'orig_md5': util.ComputeMD5Hex('original image data'),
               'tn_size': 5 * 1024,
               'med_size': 10 * 1024,
               'full_size': 150 * 1024,
               'orig_size': 1200 * 1024,
               'photo_id': photo_id}

    self._tester.UploadEpisode(self._cookie, ep_dict, [ph_dict])
    self._tester.UpdateEpisode(self._cookie, episode_id, description='A newly added description')
예제 #23
0
    def testUpdateAttribute(self):
        """Verify update of a photo attribute."""
        def _OnUpdate(p):
            p.aspect_ratio = None
            p.Update(self._client, self.stop)

        def _OnQuery(p):
            p.content_type = 'image/png'
            p.Update(self._client, partial(_OnUpdate, p))

        def _OnCreatePhoto(p):
            Photo.Query(self._client, p.photo_id, None, _OnQuery)

        photo_id = Photo.ConstructPhotoId(time.time(),
                                          self._mobile_dev.device_id, 1)
        episode_id = Episode.ConstructEpisodeId(time.time(),
                                                self._mobile_dev.device_id, 2)
        p_dict = {
            'photo_id': photo_id,
            'episode_id': episode_id,
            'user_id': self._user.user_id,
            'caption': 'A Photo'
        }
        Photo.CreateNew(self._client, callback=_OnCreatePhoto, **p_dict)
예제 #24
0
def _ValidateAutoSave(tester, user_id, device_id, request_dict):
    """Validates that the shared photos have been saved to the default viewpoint of any follower
  that has the target viewpoint marked as "auto-save".
  """
    from viewfinder.backend.www.test.save_photos_test import _ValidateSavePhotos
    validator = tester.validator

    # Validate auto-save.
    follower_matches = lambda f: f.viewpoint_id == request_dict['viewpoint_id']
    for follower in validator.QueryModelObjects(Follower,
                                                predicate=follower_matches):
        # Only validate current followers that have viewpoint marked as auto-save.
        if not follower.ShouldAutoSave() or follower.IsRemoved():
            continue

        follower_user = tester._RunAsync(User.Query, validator.client,
                                         follower.user_id, None)

        # Skip validation of follower that is sharing from default viewpoint.
        source_episodes = [
            validator.GetModelObject(Episode, ep_dict['existing_episode_id'])
            for ep_dict in request_dict['episodes']
        ]
        if all(ep.viewpoint_id == follower_user.private_vp_id
               for ep in source_episodes):
            continue

        # The share_existing op triggered a save_photos op, so wait for that to complete.
        tester._RunAsync(OpManager.Instance().WaitForUserOps, validator.client,
                         follower.user_id)

        # Get the ids of episodes that should have been created during the auto-save.
        expected_asset_id = follower_user.asset_id_seq

        save_request_dict = deepcopy(request_dict)

        # Iterate backwards, since last episode should have used last asset id.
        for ep_dict in reversed(save_request_dict['episodes']):
            # The share_existing "new_episode_id" becomes the "existing_episode_id" for save_photos.
            ep_dict['existing_episode_id'] = ep_dict['new_episode_id']

            # If target episode already existed, that should have been used.
            episode_matches = lambda e: e.user_id == follower.user_id and e.parent_ep_id == ep_dict[
                'existing_episode_id']
            episodes = validator.QueryModelObjects(Episode,
                                                   predicate=episode_matches)
            if episodes:
                ep_dict['new_episode_id'] = episodes[0].episode_id
            else:
                expected_asset_id -= 1
                timestamp, _, _ = Episode.DeconstructEpisodeId(
                    ep_dict['existing_episode_id'])
                ep_dict['new_episode_id'] = Episode.ConstructEpisodeId(
                    timestamp, follower_user.webapp_dev_id, expected_asset_id)

        # Create expected activity dict for the save_photos op.
        expected_asset_id -= 1
        save_activity_id = Activity.ConstructActivityId(
            request_dict['activity']['timestamp'], follower_user.webapp_dev_id,
            expected_asset_id)
        save_request_dict['activity']['activity_id'] = save_activity_id

        # Create expected operation id for the save_photos op.
        expected_asset_id -= 1
        save_op_id = Operation.ConstructOperationId(
            follower_user.webapp_dev_id, expected_asset_id)
        save_request_dict['headers']['op_id'] = save_op_id

        _ValidateSavePhotos(tester, follower.user_id,
                            follower_user.webapp_dev_id, save_request_dict)
예제 #25
0
    def disabled_t_estPlacemarkQueries(self):
        """Tests placemark queries."""
        def _QueryAndVerify(episode_ids, barrier_cb, search, matches):
            def _Verify(keys):
                ids = [key.hash_key for key in keys]
                self.assertEqual(len(ids), len(matches))
                [self.assertTrue(episode_ids[m] in ids) for m in matches]
                barrier_cb()

            Episode.IndexQueryKeys(self._client, ('episode.placemark={s}', {
                's': search
            }),
                                   callback=_Verify)

        def _OnCreate(locations, episodes):
            with util.Barrier(self.stop) as b:
                episode_ids = dict([(v.title, v.episode_id) for v in episodes])
                _QueryAndVerify(episode_ids, b.Callback(), 'Broadway',
                                ['kimball ph'])
                _QueryAndVerify(episode_ids, b.Callback(), '682 Broadway',
                                ['kimball ph'])
                _QueryAndVerify(episode_ids, b.Callback(), 'Broadway 682', [])
                _QueryAndVerify(episode_ids, b.Callback(),
                                'new york, ny, united states', [
                                    'kimball ph', 'bond st sushi',
                                    'viewfinder', 'soho house', 'google'
                                ])
                _QueryAndVerify(episode_ids, b.Callback(), 'new york, ny', [
                    'kimball ph', 'bond st sushi', 'viewfinder', 'soho house',
                    'google'
                ])
                _QueryAndVerify(
                    episode_ids, b.Callback(), 'NY, United States', [
                        'kimball ph', 'bond st sushi', 'viewfinder',
                        'soho house', 'google', 'kimball east', 'surf lodge'
                    ])
                _QueryAndVerify(episode_ids, b.Callback(), 'United States', [
                    'kimball ph', 'bond st sushi', 'viewfinder', 'soho house',
                    'google', 'kimball east', 'surf lodge'
                ])
                _QueryAndVerify(episode_ids, b.Callback(), 'Bahamas',
                                ['atlantis'])
                _QueryAndVerify(episode_ids, b.Callback(), 'Dominican',
                                ['casa kimball'])
                _QueryAndVerify(episode_ids, b.Callback(),
                                'Dominican Republic', ['casa kimball'])
                _QueryAndVerify(episode_ids, b.Callback(), 'Cabrera',
                                ['casa kimball'])
                _QueryAndVerify(episode_ids, b.Callback(), 'DR',
                                ['casa kimball'])

        locations = {
            'kimball ph':
            Placemark('US', 'United States', 'NY', 'New York', 'NoHo',
                      'Broadway', '682'),
            'bond st sushi':
            Placemark('US', 'United States', 'NY', 'New York', 'NoHo',
                      'Bond St', '6'),
            'viewfinder':
            Placemark('US', 'United States', 'NY', 'New York', 'SoHo',
                      'Grand St', '154'),
            'soho house':
            Placemark('US', 'United States', 'NY', 'New York',
                      'Meatpacking District', '9th Avenue', '29-35'),
            'google':
            Placemark('US', 'United States', 'NY', 'New York', 'Chelsea',
                      '8th Avenue', '111'),
            'kimball east':
            Placemark('US', 'United States', 'NY', 'East Hampton',
                      'Northwest Harbor', 'Milina', '35'),
            'surf lodge':
            Placemark('US', 'United States', 'NY', 'Montauk', '',
                      'Edgemere St', '183'),
            'casa kimball':
            Placemark('DR', 'Dominican Republic', 'Maria Trinidad Sanchez',
                      'Cabrera', 'Orchid Bay Estates', '', '5-6'),
            'atlantis':
            Placemark('BS', 'Bahamas', '', 'Paradise Island', '', '', '')
        }
        with util.ArrayBarrier(partial(_OnCreate, locations)) as b:
            device_episode_id = 0
            for place, placemark in locations.items():
                device_episode_id += 1
                timestamp = time.time()
                episode_id = Episode.ConstructEpisodeId(
                    timestamp, 1, device_episode_id)
                episode = Episode.CreateFromKeywords(
                    timestamp=timestamp,
                    episode_id=episode_id,
                    user_id=self._user.user_id,
                    viewpoint_id=self._user.private_vp_id,
                    publish_timestamp=timestamp,
                    title=place,
                    placemark=placemark)
                episode.Update(self._client, b.Callback())
예제 #26
0
    def testAlertText(self):
        """Verify the alert text for various activity types."""
        def _Test(expected_text, activity_func, client_id, sharer, viewpoint,
                  *args, **kwargs):
            timestamp = time.time()
            activity_id = Activity.ConstructActivityId(timestamp, 1, client_id)

            activity = self._RunAsync(activity_func, self._client,
                                      sharer.user_id, 'v0', activity_id,
                                      timestamp, 0, *args, **kwargs)

            alert_text = self._RunAsync(AlertManager._FormatAlertText,
                                        self._client, viewpoint, activity)

            self.assertEqual(alert_text, expected_text)

        self._validate = False

        # Create user with no given name.
        user_dict = {
            'name': 'Andy Kimball',
            'email': '*****@*****.**',
            'verified_email': True
        }
        andy_user, _ = self._tester.RegisterGoogleUser(user_dict)

        # Create user with email.
        user_dict = {
            'email': '*****@*****.**',
            'verified_email': True,
            'gender': 'Male'
        }
        andy_email, _ = self._tester.RegisterGoogleUser(user_dict)

        # Create user with no name and no email.
        user_dict = {
            'id': 1234,
            'picture': {
                'data': {
                    'url': 'http://facebook.com/user2'
                }
            }
        }
        no_name, _ = self._tester.RegisterFacebookUser(user_dict)

        # Create viewpoint with no title.
        vp_dicts = {
            'viewpoint_id': 'vp1',
            'user_id': 1,
            'timestamp': time.time(),
            'type': Viewpoint.EVENT
        }
        vp_no_title, _ = self._RunAsync(Viewpoint.CreateNew, self._client,
                                        **vp_dicts)

        # Create viewpoint with title.
        vp_title, _ = self._RunAsync(Viewpoint.CreateNew,
                                     self._client,
                                     title='Some title',
                                     **vp_dicts)

        # ------------------------------
        # Test share_existing alert text (no viewpoint title).
        # ------------------------------
        ep_dicts = [{
            'new_episode_id':
            Episode.ConstructEpisodeId(time.time(), 1, 1),
            'photo_ids': [10, 11]
        }]
        _Test('Spencer shared 2 photos', Activity.CreateShareExisting, 1,
              self._test_user, vp_no_title, ep_dicts)

        # ------------------------------
        # Test share_existing alert text (with viewpoint title).
        # ------------------------------
        ep_dicts = [{
            'new_episode_id':
            Episode.ConstructEpisodeId(time.time(), 1, 1),
            'photo_ids': [11]
        }]
        _Test('Andy Kimball shared 1 photo to: "Some title"',
              Activity.CreateShareExisting, 2, andy_user, vp_title, ep_dicts)

        # ------------------------------
        # Test share_new alert text (no viewpoint title).
        # ------------------------------
        ep_dicts = [{
            'new_episode_id':
            Episode.ConstructEpisodeId(time.time(), 1, 1),
            'photo_ids': [10]
        }]
        _Test('Andy Kimball shared 1 photo', Activity.CreateShareNew, 3,
              andy_user, vp_no_title, ep_dicts, [10])

        # ------------------------------
        # Test share_new alert text (with viewpoint title).
        # ------------------------------
        ep_dicts = [{
            'new_episode_id':
            Episode.ConstructEpisodeId(time.time(), 1, 1),
            'photo_ids': [10, 11]
        }]
        _Test('[email protected] started a conversation: "Some title"',
              Activity.CreateShareNew, 4, andy_email, vp_title, ep_dicts, [10])

        # ------------------------------
        # Test share_new alert text (no title, no photos).
        # ------------------------------
        _Test('A friend added you to a conversation', Activity.CreateShareNew,
              5, no_name, vp_no_title, [], [10])

        # ------------------------------
        # Test post_comment alert text.
        # ------------------------------
        cm_dict = {
            'viewpoint_id': 'vp1',
            'comment_id': 'c0',
            'message': 'Amazing photo'
        }
        self._UpdateOrAllocateDBObject(Comment, **cm_dict)
        _Test('[email protected]: Amazing photo',
              Activity.CreatePostComment, 6, andy_email, vp_title, cm_dict)

        # ------------------------------
        # Test add_followers alert text (no viewpoint title).
        # ------------------------------
        _Test('Spencer added you to a conversation',
              Activity.CreateAddFollowers, 8, self._test_user, vp_no_title,
              [andy_user.user_id])

        # ------------------------------
        # Test add_followers alert text (with viewpoint title).
        # ------------------------------
        _Test('Andy Kimball added you to a conversation: "Some title"',
              Activity.CreateAddFollowers, 9, andy_user, vp_title,
              [100, andy_email.user_id])
예제 #27
0
    def testAlertEmail(self):
        """Verify the alert email for various activity types."""
        def _Test(client_id, timestamp, vp_dict, episode_id, ph_dict):
            ep_dict = {
                'new_episode_id': episode_id,
                'photo_ids':
                [ph_dict['photo_id']] if ph_dict is not None else []
            }
            activity_id = Activity.ConstructActivityId(timestamp, 1, client_id)
            activity = self._RunAsync(Activity.CreateShareNew,
                                      self._client,
                                      user_id=self._test_user.user_id,
                                      viewpoint_id='v0',
                                      activity_id=activity_id,
                                      timestamp=timestamp,
                                      update_seq=0,
                                      ep_dicts=[ep_dict],
                                      follower_ids=[self._test_user2.user_id])

            viewpoint, _ = self._RunAsync(Viewpoint.CreateNew, self._client,
                                          **vp_dict)
            if ph_dict is not None:
                photo = Photo.CreateFromKeywords(**ph_dict)
                self._RunAsync(photo.Update, self._client)
                viewpoint.cover_photo = {
                    'episode_id': episode_id,
                    'photo_id': photo.photo_id
                }

            return self._RunAsync(AlertManager._FormatAlertEmail, self._client,
                                  self._test_user2.user_id, viewpoint,
                                  activity)

        self._validate = False

        # ------------------------------
        # Test cover photo (aspect ratio = 0.5).
        # ------------------------------
        timestamp = 1361931773
        vp_dict = {
            'viewpoint_id': 'vp1',
            'user_id': 1,
            'timestamp': timestamp,
            'type': Viewpoint.EVENT
        }
        episode_id = Episode.ConstructEpisodeId(timestamp, 1, 1)
        ph_dict = {'photo_id': 'p10', 'aspect_ratio': 0.5}
        email_args = _Test(1, timestamp, vp_dict, episode_id, ph_dict)
        self.assertEqual(email_args['toname'], 'Peter Mattis')
        self.assertEqual(email_args['from'], '*****@*****.**')
        self.assertEqual(email_args['fromname'],
                         'Spencer Kimball via Viewfinder')
        self.assertEqual(email_args['to'], '*****@*****.**')

        html = email_args['html']
        text = email_args['text']

        # ------------------------------
        # Test for name, cover photo url, viewpoint url, and unsubscribe url.
        # ------------------------------
        self.assertIn('Spencer Kimball', html)
        self.assertIn('Spencer Kimball', text)
        self.assertIsNotNone(
            re.match(r'.*\?next=%2Fepisodes%2Fefh9H-V30%2Fphotos%2Fp10\.f.*',
                     html))
        self.assertIsNotNone(re.match(r'.*/pr/.{10}\".*', html))
        self.assertIn('/pr/', text)
        self.assertIsNotNone(re.match(r'.*\/unsubscribe\?cookie=', html))
        self.assertIn('height="416"', html)
        self.assertIn('width="208"', html)

        # ------------------------------
        # Test cover photo (aspect ratio = 2).
        # ------------------------------
        ph_dict = {'photo_id': 'p10', 'aspect_ratio': 2}
        email_args = _Test(1, timestamp, vp_dict, episode_id, ph_dict)
        self.assertIn('height="208"', email_args['html'])
        self.assertIn('width="416"', email_args['html'])
        self.assertIn('View All Photos', email_args['html'])

        # ------------------------------
        # Test no cover photo.
        # ------------------------------
        episode_id = Episode.ConstructEpisodeId(timestamp, 1, 2)
        email_args = _Test(2, timestamp, vp_dict, episode_id, ph_dict=None)
        self.assertNotIn('efh9H-V31%2Fphotos', email_args['html'])
        self.assertIn('View Conversation', email_args['html'])

        # ------------------------------
        # Test for no conversation title.
        # ------------------------------
        vp_dict = {
            'viewpoint_id': 'vp1',
            'user_id': 1,
            'timestamp': timestamp,
            'type': Viewpoint.EVENT
        }
        email_args = _Test(3, timestamp, vp_dict, episode_id, ph_dict)
        self.assertNotIn('Test_Conversation_Title', email_args['html'])
        self.assertNotIn('Test_Conversation_Title', email_args['text'])

        # ------------------------------
        # Test for presence of conversation title.
        # ------------------------------
        vp_dict = {
            'viewpoint_id': 'vp1',
            'user_id': 1,
            'timestamp': timestamp,
            'type': Viewpoint.EVENT,
            'title': 'Test_Conversation_Title'
        }
        email_args = _Test(4, timestamp, vp_dict, episode_id, ph_dict)
        self.assertIn('Test_Conversation_Title', email_args['html'])
        self.assertIn('Test_Conversation_Title', email_args['text'])
예제 #28
0
    def testAssetIdAltDevice(self):
        """Test construction of assets using a different device than the calling device."""
        # ------------------------------
        # Try to upload using a device not owned by the user at all.
        # ------------------------------
        ep_dict = self._CreateEpisodeDict(self._cookie)
        ep_dict['episode_id'] = Episode.ConstructEpisodeId(
            time.time(), self._device_ids[2], self._test_id)
        self._test_id += 1

        ph_dict = self._CreatePhotoDict(self._cookie)
        ph_dict['photo_id'] = Photo.ConstructPhotoId(time.time(),
                                                     self._device_ids[2],
                                                     self._test_id)
        self._test_id += 1

        self.assertRaisesHttpError(403, self._tester.UploadEpisode,
                                   self._cookie, ep_dict, [ph_dict])

        # ------------------------------
        # Upload using alternate devices owned by the user.
        # ------------------------------
        ep_dict = self._CreateEpisodeDict(self._cookie)
        ep_dict['episode_id'] = Episode.ConstructEpisodeId(
            time.time(), self._extra_device_id1, self._test_id)
        self._test_id += 1

        ph_dict = self._CreatePhotoDict(self._cookie)
        ph_dict['photo_id'] = Photo.ConstructPhotoId(time.time(),
                                                     self._extra_device_id2,
                                                     self._test_id)
        self._test_id += 1

        act_dict = self._tester.CreateActivityDict(self._cookie)
        act_dict['activity_id'] = Activity.ConstructActivityId(
            time.time(), self._extra_device_id1, self._test_id)
        self._test_id += 1

        self._tester.UploadEpisode(self._cookie, ep_dict, [ph_dict], act_dict)

        # ------------------------------
        # Share to a new viewpoint using alternate devices owned by the user.
        # ------------------------------
        viewpoint_id = Viewpoint.ConstructViewpointId(self._extra_device_id2,
                                                      self._test_id)
        self._test_id += 1

        self._tester.ShareNew(self._cookie,
                              [(ep_dict['episode_id'], [ph_dict['photo_id']])],
                              [self._user2.user_id],
                              viewpoint_id=viewpoint_id)

        # ------------------------------
        # Post to the new viewpoint using alternate devices owned by the user.
        # ------------------------------
        comment_id = Comment.ConstructCommentId(time.time(),
                                                self._extra_device_id1,
                                                self._test_id)
        self._test_id += 1

        self._tester.PostComment(self._cookie, viewpoint_id, 'hi')
예제 #29
0
    def testPostIdOrdering(self):
        """Verify that post_id sorts like (episode_id, photo_id) does."""
        def _Compare(episode_id1, photo_id1, episode_id2, photo_id2):
            result = cmp(episode_id1, episode_id2)
            if result == 0:
                result = cmp(photo_id1, photo_id2)

            post_id1 = Post.ConstructPostId(episode_id1, photo_id1)
            post_id2 = Post.ConstructPostId(episode_id2, photo_id2)
            self.assertEqual(cmp(post_id1, post_id2), result)

        timestamp = time.time()

        episode_id1 = Episode.ConstructEpisodeId(timestamp, 1, (127, None))
        episode_id2 = Episode.ConstructEpisodeId(timestamp, 1, (128, None))
        photo_id1 = Photo.ConstructPhotoId(timestamp, 1, 128)
        photo_id2 = Photo.ConstructPhotoId(timestamp, 1, 127)
        _Compare(episode_id1, photo_id1, episode_id2, photo_id2)

        episode_id1 = Episode.ConstructEpisodeId(timestamp, 127, 1)
        episode_id2 = Episode.ConstructEpisodeId(timestamp, 128, 1)
        photo_id1 = Photo.ConstructPhotoId(timestamp, 128, (1, None))
        photo_id2 = Photo.ConstructPhotoId(timestamp, 127, (1, None))
        _Compare(episode_id1, photo_id1, episode_id2, photo_id2)

        episode_id1 = Episode.ConstructEpisodeId(timestamp, 0, 0)
        episode_id2 = Episode.ConstructEpisodeId(timestamp, 0, 0)
        photo_id1 = Photo.ConstructPhotoId(timestamp, 0, 0)
        photo_id2 = Photo.ConstructPhotoId(timestamp, 0, 0)
        _Compare(episode_id1, photo_id1, episode_id2, photo_id2)

        episode_id1 = Episode.ConstructEpisodeId(timestamp, 1, 0)
        episode_id2 = Episode.ConstructEpisodeId(timestamp, 1, 1)
        photo_id1 = Photo.ConstructPhotoId(timestamp, 1, 1)
        photo_id2 = Photo.ConstructPhotoId(timestamp, 1, 0)
        _Compare(episode_id1, photo_id1, episode_id2, photo_id2)

        episode_id1 = Episode.ConstructEpisodeId(0, 0, 0)
        episode_id2 = Episode.ConstructEpisodeId(1, 0, 0)
        photo_id1 = Photo.ConstructPhotoId(1, 0, (0, None))
        photo_id2 = Photo.ConstructPhotoId(0, 0, (0, None))
        _Compare(episode_id1, photo_id1, episode_id2, photo_id2)

        episode_id1 = Episode.ConstructEpisodeId(timestamp, 0, (0, '1'))
        episode_id2 = Episode.ConstructEpisodeId(timestamp, 0, (0, '2'))
        photo_id1 = Photo.ConstructPhotoId(timestamp, 0, (0, None))
        photo_id2 = Photo.ConstructPhotoId(timestamp, 0, (0, None))
        _Compare(episode_id1, photo_id1, episode_id2, photo_id2)

        episode_id1 = Episode.ConstructEpisodeId(timestamp, 0, 0)
        episode_id2 = Episode.ConstructEpisodeId(timestamp, 0, 0)
        photo_id1 = Photo.ConstructPhotoId(timestamp, 0, (0, u'ab'))
        photo_id2 = Photo.ConstructPhotoId(timestamp, 0, (0, u'cd'))
        _Compare(episode_id1, photo_id1, episode_id2, photo_id2)
예제 #30
0
    def disabled_t_estLocationQueries(self):
        """Tests location queries."""
        def _QueryAndVerify(episode_ids, barrier_cb, loc_search, matches):
            def _Verify(keys):
                ids = [key.hash_key for key in keys]
                self.assertEqual(len(ids), len(matches))
                [self.assertTrue(episode_ids[m] in ids) for m in matches]
                barrier_cb()

            Episode.IndexQueryKeys(self._client, 'episode.location="%f,%f,%f"' % \
                                   (loc_search[0], loc_search[1], loc_search[2]), callback=_Verify)

        def _OnCreate(locations, episodes):
            with util.Barrier(self.stop) as b:
                episode_ids = dict([(v.title, v.episode_id) for v in episodes])
                # Exact search.
                _QueryAndVerify(episode_ids, b.Callback(),
                                Location(40.727657, -73.994583, 30),
                                ['kimball ph'])
                _QueryAndVerify(episode_ids, b.Callback(),
                                Location(41.044048, -71.950622, 100),
                                ['surf lodge'])
                # A super-small search area, centered in middle of Great Jones Alley.
                _QueryAndVerify(episode_ids, b.Callback(),
                                Location(40.727267, -73.994443, 10), [])
                # Widen the search area to 50m, centered in middle of Great Jones Alley.
                _QueryAndVerify(episode_ids, b.Callback(),
                                Location(40.727267, -73.994443, 50),
                                ['kimball ph', 'bond st sushi'])
                # Union square with a 2km radius.
                _QueryAndVerify(episode_ids, b.Callback(),
                                Location(40.736462, -73.990517, 2000), [
                                    'kimball ph', 'bond st sushi',
                                    'viewfinder', 'soho house', 'google'
                                ])
                # The Dominican Republic.
                _QueryAndVerify(episode_ids, b.Callback(),
                                Location(19.041349, -70.427856, 75000),
                                ['casa kimball'])
                # The Caribbean.
                _QueryAndVerify(episode_ids, b.Callback(),
                                Location(22.593726, -76.662598, 800000),
                                ['casa kimball', 'atlantis'])
                # Long Island.
                _QueryAndVerify(episode_ids, b.Callback(),
                                Location(40.989228, -72.144470, 40000),
                                ['kimball east', 'surf lodge'])

        locations = {
            'kimball ph': Location(40.727657, -73.994583, 50.0),
            'bond st sushi': Location(40.726901, -73.994358, 50.0),
            'viewfinder': Location(40.720169, -73.998756, 200.0),
            'soho house': Location(40.740616, -74.005880, 200.0),
            'google': Location(40.740974, -74.002115, 500.0),
            'kimball east': Location(41.034184, -72.210603, 50.0),
            'surf lodge': Location(41.044048, -71.950622, 100.0),
            'casa kimball': Location(19.636848, -69.896602, 100.0),
            'atlantis': Location(25.086104, -77.323065, 1000.0)
        }
        with util.ArrayBarrier(partial(_OnCreate, locations)) as b:
            device_episode_id = 0
            for place, location in locations.items():
                device_episode_id += 1
                timestamp = time.time()
                episode_id = Episode.ConstructEpisodeId(
                    timestamp, 1, device_episode_id)
                episode = Episode.CreateFromKeywords(
                    timestamp=timestamp,
                    episode_id=episode_id,
                    user_id=self._user.user_id,
                    viewpoint_id=self._user.private_vp_id,
                    publish_timestamp=timestamp,
                    title=place,
                    location=location)
                episode.Update(self._client, b.Callback())