Ejemplo n.º 1
0
    def test_multiple_profiles(self):
        """Exercise multiple profiles and collections"""
        expected_count_all = 0
        profiles_count = 5
        collection_names = ( 'testing', 'keys', 'tabs', 'history', 'bookmarks' )
        collection_counts = {}

        # Produce a set of Profiles in the datastore
        profiles = []
        for i in range(profiles_count):
            profile = Profile(user_name='t-%s'%i, user_id='id-%s'%i, password='******'%i)
            profile.put()
            profiles.append(profile)

        # Generate collections for each profile.
        for p in profiles:
            auth_header = self.build_auth_header(p.user_name, p.password)
            collection_counts[p.user_name] = {}

            # Run through several collections and make WBOs
            for cn in collection_names:

                curr_count = random.randint(1,10)
                collection_counts[p.user_name][cn] = curr_count
                expected_count_all += curr_count

                # Generate a bunch of random-content WBOs
                base_url = '/sync/1.0/%s/storage/%s' % (p.user_name, cn)
                for i in range(curr_count):
                    resp = self.put_random_wbo(base_url, auth_header)

        # Ensure the total number of WBOs is correct.
        result_count_all = WBO.all().count()
        self.assertEqual(expected_count_all, result_count_all)

        # Ensure the counts for each profile collection matches inserts.
        for profile in profiles:
            counts = Collection.get_counts(profile)
            for name in collection_names:
                c = Collection.get_by_profile_and_name(profile, name)
                self.assertEqual(
                    collection_counts[profile.user_name][name],
                    WBO.get_by_collection(c).count()
                )

        # Delete each of the collections for each user.
        for profile in profiles:
            auth_header = self.build_auth_header(
                profile.user_name, profile.password
            )
            for name in collection_names:
                url = '/sync/1.0/%s/storage/%s' % (profile.user_name, name)
                resp = self.app.delete(url, headers=auth_header)
                # Ensure the individual collection is now empty.
                c = Collection.get_by_profile_and_name(profile, name)
                self.assertEqual(0, WBO.get_by_collection(c).count())

        # Ensure there are no more WBOs
        result_count_all = WBO.all().count()
        self.assertEqual(0, result_count_all)
Ejemplo n.º 2
0
    def setUp(self):
        """Prepare for unit test"""
        self.log = logging.getLogger()
        self.log.setLevel(logging.DEBUG)

        # There shouldn't already be a profile, but just in case...
        profile = Profile.get_by_user_name(self.USER_NAME)
        if profile: profile.delete()

        # Create a new profile for tests.
        self.profile = p = Profile(user_name=self.USER_NAME,
                                   user_id='8675309',
                                   password=self.PASSWD)
        self.profile.put()

        self.auth_header = self.build_auth_header(p.user_name, p.password)

        self.collection = Collection.get_by_profile_and_name(p, 'testing')

        self.wbo_values = [
            dict(zip(self.value_keys, value_set))
            for value_set in self.value_sets
        ]
        for w in self.wbo_values:
            w['payload'] = simplejson.dumps({'stuff': w['payload']})

        # Build the app test harness.
        self.app = webtest.TestApp(sync_api.application())
Ejemplo n.º 3
0
    def cb(wh, *args, **kwargs):
        url_user = urllib.unquote(args[0])

        auth_header = wh.request.headers.get('Authorization')
        if auth_header == None:
            wh.response.set_status(401, message="Authorization Required")
            wh.response.headers['WWW-Authenticate'] = 'Basic realm="firefox-sync"'
            return
        
        auth_parts = auth_header.split(' ')
        user_arg, pass_arg = base64.b64decode(auth_parts[1]).split(':')

        valid_authen = (
            (url_user == user_arg) 
                and 
            Profile.authenticate(user_arg, pass_arg)
        )

        if not valid_authen:
            wh.response.set_status(401, message="Authorization Required")
            wh.response.headers['WWW-Authenticate'] = 'Basic realm="firefox-sync"'
            wh.response.out.write("Unauthorized")
        else:
            wh.request.profile = Profile.get_by_user_name(user_arg)
            return func(wh, *args, **kwargs)
Ejemplo n.º 4
0
    def test_multiple_profiles(self):
        """Exercise multiple profiles and collections"""
        expected_count_all = 0
        profiles_count = 5
        collection_names = ('testing', 'keys', 'tabs', 'history', 'bookmarks')
        collection_counts = {}

        # Produce a set of Profiles in the datastore
        profiles = []
        for i in range(profiles_count):
            profile = Profile(user_name='t-%s' % i,
                              user_id='id-%s' % i,
                              password='******' % i)
            profile.put()
            profiles.append(profile)

        # Generate collections for each profile.
        for p in profiles:
            auth_header = self.build_auth_header(p.user_name, p.password)
            collection_counts[p.user_name] = {}

            # Run through several collections and make WBOs
            for cn in collection_names:

                curr_count = random.randint(1, 10)
                collection_counts[p.user_name][cn] = curr_count
                expected_count_all += curr_count

                # Generate a bunch of random-content WBOs
                base_url = '/sync/1.0/%s/storage/%s' % (p.user_name, cn)
                for i in range(curr_count):
                    resp = self.put_random_wbo(base_url, auth_header)

        # Ensure the total number of WBOs is correct.
        result_count_all = WBO.all().count()
        self.assertEqual(expected_count_all, result_count_all)

        # Ensure the counts for each profile collection matches inserts.
        for profile in profiles:
            counts = Collection.get_counts(profile)
            for name in collection_names:
                c = Collection.get_by_profile_and_name(profile, name)
                self.assertEqual(collection_counts[profile.user_name][name],
                                 WBO.get_by_collection(c).count())

        # Delete each of the collections for each user.
        for profile in profiles:
            auth_header = self.build_auth_header(profile.user_name,
                                                 profile.password)
            for name in collection_names:
                url = '/sync/1.0/%s/storage/%s' % (profile.user_name, name)
                resp = self.app.delete(url, headers=auth_header)
                # Ensure the individual collection is now empty.
                c = Collection.get_by_profile_and_name(profile, name)
                self.assertEqual(0, WBO.get_by_collection(c).count())

        # Ensure there are no more WBOs
        result_count_all = WBO.all().count()
        self.assertEqual(0, result_count_all)
Ejemplo n.º 5
0
    def test_cascading_profile_delete(self):
        """Ensure that profile deletion cascades down to collections and WBOs"""
        (p, c, ah) = (self.profile, self.collection, self.auth_header)
        wbos = self.build_wbo_set()

        self.assert_(WBO.all().count() > 0)
        self.assert_(Collection.all().count() > 0)
        self.assert_(Profile.all().count() > 0)

        p.delete()

        self.assertEquals(0, WBO.all().count())
        self.assertEquals(0, Collection.all().count())
        self.assertEquals(0, Profile.all().count())
Ejemplo n.º 6
0
    def test_cascading_profile_delete(self):
        """Ensure that profile deletion cascades down to collections and WBOs"""
        (p, c, ah) = (self.profile, self.collection, self.auth_header)
        wbos = self.build_wbo_set()

        self.assert_(WBO.all().count() > 0)
        self.assert_(Collection.all().count() > 0)
        self.assert_(Profile.all().count() > 0)

        p.delete()

        self.assertEquals(0, WBO.all().count())
        self.assertEquals(0, Collection.all().count())
        self.assertEquals(0, Profile.all().count())
Ejemplo n.º 7
0
    def setUp(self):
        """Prepare for unit test"""
        self.log = logging.getLogger()
        self.log.setLevel(logging.DEBUG)
        
        # There shouldn't already be a profile, but just in case...
        profile = Profile.get_by_user_name(self.USER_NAME)
        if profile: profile.delete()

        # Create a new profile for tests.
        self.profile = p = Profile(
            user_name = self.USER_NAME,
            user_id   = '8675309',
            password  = self.PASSWD
        )
        self.profile.put()

        self.auth_header = self.build_auth_header(p.user_name, p.password)

        self.collection = Collection.get_by_profile_and_name(p, 'testing')

        self.wbo_values = [
            dict(zip(self.value_keys, value_set))
            for value_set in self.value_sets
        ]
        for w in self.wbo_values:
            w['payload'] = simplejson.dumps({ 'stuff': w['payload'] })
        
        # Build the app test harness.
        self.app = webtest.TestApp(sync_api.application())
Ejemplo n.º 8
0
    def post(self):
        """Process a POST'd command from the sync start page.

        HACK: This is a little hacky, pivoting on a form field command, but oh well.
        """
        user, profile = Profile.get_user_and_profile()
        action = self.request.get('action', False)

        if not profile and 'create_profile' == action:

            # Create a new profile, with auto-generated password
            new_profile = Profile(user=user,
                                  user_id=user.user_id(),
                                  user_name=hashlib.md5(
                                      user.user_id()).hexdigest(),
                                  password=Profile.generate_password())
            new_profile.put()

        elif profile and 'regenerate_password' == action:
            # Generate and set a new password for the profile
            profile.password = Profile.generate_password()
            profile.put()

        elif profile and 'delete_profile' == action:
            # Delete the profile
            profile.delete()

        return self.redirect('/start')
Ejemplo n.º 9
0
 def get(self):
     """Display the sync start page"""
     user, profile = Profile.get_user_and_profile()
     return self.render_template('main/start.html', {
         'user': user, 
         'profile': profile,
         'sync_url': '%s/sync/' % self.request.application_url,
         'logout_url': users.create_logout_url(self.request.uri)
     })
Ejemplo n.º 10
0
 def get(self):
     """Display the sync start page"""
     user, profile = Profile.get_user_and_profile()
     return self.render_template(
         'main/start.html', {
             'user': user,
             'profile': profile,
             'sync_url': '%s/sync/' % self.request.application_url,
             'logout_url': users.create_logout_url(self.request.uri)
         })
Ejemplo n.º 11
0
    def post(self):
        """Process a POST'd command from the sync start page.

        HACK: This is a little hacky, pivoting on a form field command, but oh well.
        """
        user, profile = Profile.get_user_and_profile()
        action = self.request.get('action', False)

        if not profile and 'create_profile' == action:
            
            # Create a new profile, with auto-generated password
            new_profile = Profile(
                user      = user,
                user_id   = user.user_id(),
                user_name = hashlib.md5(user.user_id()).hexdigest(),
                password  = Profile.generate_password()
            )
            new_profile.put()

        elif profile and 'regenerate_password' == action:
            # Generate and set a new password for the profile
            profile.password = Profile.generate_password()
            profile.put()

        elif profile and 'delete_profile' == action:
            # Delete the profile
            profile.delete()

        return self.redirect('/start')
Ejemplo n.º 12
0
    def cb(wh, *args, **kwargs):
        url_user = urllib.unquote(args[0])

        auth_header = wh.request.headers.get('Authorization')
        if auth_header == None:
            wh.response.set_status(401, message="Authorization Required")
            wh.response.headers[
                'WWW-Authenticate'] = 'Basic realm="firefox-sync"'
            return

        auth_parts = auth_header.split(' ')
        user_arg, pass_arg = base64.b64decode(auth_parts[1]).split(':')

        valid_authen = ((url_user == user_arg)
                        and Profile.authenticate(user_arg, pass_arg))

        if not valid_authen:
            wh.response.set_status(401, message="Authorization Required")
            wh.response.headers[
                'WWW-Authenticate'] = 'Basic realm="firefox-sync"'
            wh.response.out.write("Unauthorized")
        else:
            wh.request.profile = Profile.get_by_user_name(user_arg)
            return func(wh, *args, **kwargs)
Ejemplo n.º 13
0
    def test_collection_counts_and_timestamps(self):
        """Exercise collection counts and timestamps"""
        profile = Profile(user_name='tester-1',
                          user_id='8675309',
                          password='******')
        profile.put()

        auth_header = self.build_auth_header(profile.user_name,
                                             profile.password)

        expected_count_all = 0
        expected_counts = {
            'clients': 2,
            'crypto': 0,
            'forms': 6,
            'history': 0,
            'keys': 10,
            'meta': 12,
            'bookmarks': 14,
            'prefs': 16,
            'tabs': 18,
            'passwords': 20,
            'foo': 12,
            'bar': 14,
            'baz': 16
        }
        expected_dates = {}

        # Insert objects with random contents to satisfy the expected counts
        for collection_name, curr_count in expected_counts.items():
            base_url = '/sync/1.0/%s/storage/%s' % (profile.user_name,
                                                    collection_name)
            for i in range(curr_count):
                resp = self.put_random_wbo(base_url, auth_header)
                expected_dates[collection_name] = float(resp.body)
                expected_count_all += 1

        # Ensure the counts match expected
        resp = self.app.get('/sync/1.0/%s/info/collection_counts' %
                            (profile.user_name),
                            headers=auth_header)
        resp_data = simplejson.loads(resp.body)
        self.assertEqual(expected_counts, resp_data)

        # Ensure all timestamps are same or newer than expected.
        resp = self.app.get('/sync/1.0/%s/info/collections' %
                            (profile.user_name),
                            headers=auth_header)
        resp_data = simplejson.loads(resp.body)
        for k, v in expected_dates.items():
            self.assert_(k in resp_data)
            self.assert_(resp_data[k] >= expected_dates[k])

        # Verify the count of all objects after creating
        result_count = WBO.all().count()
        self.assertEqual(expected_count_all, result_count)

        # Delete each collection and verify the count after
        for collection_name, curr_count in expected_counts.items():
            url = '/sync/1.0/%s/storage/%s' % (profile.user_name,
                                               collection_name)
            resp = self.app.delete(url, headers=auth_header)
            self.assert_(WBO.get_time_now() >= float(resp.body))

            expected_count_all -= curr_count
            result_count = WBO.all().count()
            self.assertEqual(expected_count_all, result_count)

        # No WBOs should be left after all collections deleted.
        result_count = WBO.all().count()
        self.assertEqual(0, result_count)
Ejemplo n.º 14
0
    def test_collection_counts_and_timestamps(self):
        """Exercise collection counts and timestamps"""
        profile = Profile(user_name = 'tester-1', user_id='8675309', password = '******')
        profile.put()

        auth_header = self.build_auth_header(
            profile.user_name, profile.password
        )

        expected_count_all = 0
        expected_counts = {
            'clients':2, 'crypto':0, 'forms':6, 'history':0, 'keys':10,
            'meta':12, 'bookmarks':14, 'prefs':16, 'tabs':18, 'passwords':20,
            'foo':12, 'bar':14, 'baz':16
        }
        expected_dates = {}

        # Insert objects with random contents to satisfy the expected counts
        for collection_name, curr_count in expected_counts.items():
            base_url = '/sync/1.0/%s/storage/%s' % (
                profile.user_name, collection_name
            )
            for i in range(curr_count):
                resp = self.put_random_wbo(base_url, auth_header)
                expected_dates[collection_name] = float(resp.body)
                expected_count_all += 1

        # Ensure the counts match expected
        resp = self.app.get(
            '/sync/1.0/%s/info/collection_counts' % (profile.user_name),
            headers=auth_header
        )
        resp_data = simplejson.loads(resp.body)
        self.assertEqual(expected_counts, resp_data)

        # Ensure all timestamps are same or newer than expected.
        resp = self.app.get(
            '/sync/1.0/%s/info/collections' % (profile.user_name),
            headers=auth_header
        )
        resp_data = simplejson.loads(resp.body)
        for k,v in expected_dates.items():
            self.assert_(k in resp_data)
            self.assert_(resp_data[k] >= expected_dates[k])

        # Verify the count of all objects after creating
        result_count = WBO.all().count()
        self.assertEqual(expected_count_all, result_count)

        # Delete each collection and verify the count after
        for collection_name, curr_count in expected_counts.items():
            url = '/sync/1.0/%s/storage/%s' % (
                profile.user_name, collection_name
            )
            resp = self.app.delete(url, headers=auth_header)
            self.assert_(WBO.get_time_now() >= float(resp.body))

            expected_count_all -= curr_count
            result_count = WBO.all().count()
            self.assertEqual(expected_count_all, result_count)

        # No WBOs should be left after all collections deleted.
        result_count = WBO.all().count()
        self.assertEqual(0, result_count)