示例#1
0
 def test_reload_if_needed(self):
     """ Reload the cache if it's empty """
     with patch.object(SQLCache, 'storage_impl') as storage_impl:
         storage_impl().list.return_value = [
             make_package(factory=SQLPackage)
         ]
         SQLCache.reload_if_needed()
         count = self.sql.query(SQLPackage).count()
         self.assertEqual(count, 1)
示例#2
0
 def test_reload_if_needed(self):
     """ Reload the cache if it's empty """
     with patch.object(SQLCache, 'storage_impl') as storage_impl:
         storage_impl().list.return_value = [
             make_package(factory=SQLPackage)
         ]
         SQLCache.reload_if_needed()
         count = self.sql.query(SQLPackage).count()
         self.assertEqual(count, 1)
示例#3
0
class TestSQLiteCache(unittest.TestCase):
    """ Tests for the SQLAlchemy cache """

    DB_URL = "sqlite://"

    @classmethod
    def setUpClass(cls):
        super(TestSQLiteCache, cls).setUpClass()
        settings = {"pypi.storage": "tests.DummyStorage", "db.url": cls.DB_URL}
        try:
            cls.kwargs = SQLCache.configure(settings)
        except OperationalError:
            raise unittest.SkipTest("Couldn't connect to database")

    def setUp(self):
        super(TestSQLiteCache, self).setUp()
        transaction.begin()
        self.request = DummyRequest()
        self.request.tm = transaction.manager
        self.db = SQLCache(self.request, **self.kwargs)
        self.sql = self.db.db
        self.storage = self.db.storage = MagicMock(spec=IStorage)

    def tearDown(self):
        super(TestSQLiteCache, self).tearDown()
        transaction.abort()
        self.sql.query(SQLPackage).delete()
        transaction.commit()
        self.request._process_finished_callbacks()

    def test_upload(self):
        """ upload() saves package and uploads to storage """
        pkg = make_package(factory=SQLPackage)
        content = BytesIO(b"test1234")
        self.db.upload(pkg.filename, content, pkg.name, pkg.version)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
        saved_pkg = self.sql.query(SQLPackage).first()
        self.assertEqual(saved_pkg, pkg)
        # If calculate hashes is on, it'll read the data
        # and rewrap with BytesIO
        self.storage.upload.assert_called_with(pkg, ANY)

    def test_upload_overwrite(self):
        """ Uploading a preexisting packages overwrites current package """
        self.db.allow_overwrite = True
        name, filename = "a", "a-1.tar.gz"
        self.db.upload(filename, BytesIO(b"old"), name)
        self.db.upload(filename, BytesIO(b"new"), name)

        all_versions = self.db.all(name)
        self.assertEqual(len(all_versions), 1)

    def test_save(self):
        """ save() puts object into database """
        pkg = make_package(factory=SQLPackage)
        self.db.save(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
        saved_pkg = self.sql.query(SQLPackage).first()
        self.assertEqual(saved_pkg, pkg)

    def test_save_unicode(self):
        """ save() can store packages with unicode in the names """
        pkg = make_package("mypackage™", factory=SQLPackage)
        self.db.save(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
        saved_pkg = self.sql.query(SQLPackage).first()
        self.assertEqual(saved_pkg, pkg)

    def test_delete(self):
        """ delete() removes object from database and deletes from storage """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        transaction.commit()
        self.sql.add(pkg)
        self.db.delete(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 0)
        self.storage.delete.assert_called_with(pkg)

    def test_clear(self):
        """ clear() removes object from database """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        transaction.commit()
        self.sql.add(pkg)
        self.db.delete(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 0)

    def test_reload(self):
        """ reload_from_storage() inserts packages into the database """
        keys = [
            make_package(factory=SQLPackage),
            make_package(
                "mypkg2",
                "1.3.4",
                "my/other/path",
                factory=SQLPackage,
                hash_md5="md5",
                hash_sha256="sha256",
            ),
        ]
        self.storage.list.return_value = keys
        self.db.reload_from_storage()
        all_pkgs = self.sql.query(SQLPackage).all()
        self.assertItemsEqual(all_pkgs, keys)

    def test_fetch(self):
        """ fetch() retrieves a package from the database """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        saved_pkg = self.db.fetch(pkg.filename)
        self.assertEqual(saved_pkg, pkg)

    def test_fetch_missing(self):
        """ fetch() returns None if no package exists """
        saved_pkg = self.db.fetch("missing_pkg-1.2.tar.gz")
        self.assertIsNone(saved_pkg)

    def test_all_versions(self):
        """ all() returns all versions of a package """
        pkgs = [
            make_package(factory=SQLPackage),
            make_package(version="1.3", filename="mypath3",
                         factory=SQLPackage),
            make_package("mypkg2",
                         "1.3.4",
                         "my/other/path",
                         factory=SQLPackage),
        ]
        self.sql.add_all(pkgs)
        saved_pkgs = self.db.all("mypkg")
        self.assertItemsEqual(saved_pkgs, pkgs[:2])

    def test_distinct(self):
        """ distinct() returns all unique package names """
        pkgs = [
            make_package(factory=SQLPackage),
            make_package(version="1.3", filename="mypath3",
                         factory=SQLPackage),
            make_package("mypkg2",
                         "1.3.4",
                         "my/other/path",
                         factory=SQLPackage),
        ]
        self.sql.add_all(pkgs)
        saved_pkgs = self.db.distinct()
        self.assertItemsEqual(saved_pkgs, set([p.name for p in pkgs]))

    def test_search_or(self):
        """ search() returns packages that match the query """
        pkgs = [
            make_package(factory=SQLPackage),
            make_package(
                "somepackage",
                version="1.3",
                filename="mypath3",
                summary="this is mypkg",
                factory=SQLPackage,
            ),
            make_package("mypkg2",
                         "1.3.4",
                         "my/other/path",
                         factory=SQLPackage),
            make_package("package", factory=SQLPackage),
        ]
        self.sql.add_all(pkgs)
        criteria = {"name": ["mypkg"], "summary": ["mypkg"]}
        packages = self.db.search(criteria, "or")
        self.assertItemsEqual(packages, pkgs[:-1])

    def test_search_and(self):
        """ search() returns packages that match the query """
        pkgs = [
            make_package(factory=SQLPackage),
            make_package(
                "somepackage",
                version="1.3",
                filename="mypath3",
                summary="this is mypkg",
                factory=SQLPackage,
            ),
            make_package("mypkg2",
                         "1.3.4",
                         "my/other/path",
                         factory=SQLPackage),
            make_package("package", factory=SQLPackage),
        ]
        self.sql.add_all(pkgs)
        criteria = {"name": ["my", "pkg"], "summary": ["this", "mypkg"]}
        packages = self.db.search(criteria, "and")
        self.assertItemsEqual(packages, pkgs[:-1])

    def test_summary(self):
        """ summary constructs per-package metadata summary """
        self.db.upload("pkg1-0.3.tar.gz", BytesIO(b"test1234"), "pkg1", "0.3")
        self.db.upload("pkg1-1.1.tar.gz", BytesIO(b"test1234"), "pkg1", "1.1")
        p1 = self.db.upload("pkg1a2.tar.gz", BytesIO(b"test1234"), "pkg1",
                            "1.1.1a2")
        p2 = self.db.upload("pkg2.tar.gz", BytesIO(b"test1234"), "pkg2",
                            "0.1dev2")
        s1, s2 = self.db.summary()  # pylint: disable=E0632
        # Order them correctly. assertItemsEqual isn't playing nice in py2.6
        if s1["name"] == "pkg2":
            s1, s2 = s2, s1
        # last_modified may be rounded when stored in MySQL,
        # so the best we can do is make sure they're close.
        self.assertTrue(
            calendar.timegm(s1["last_modified"].timetuple()) -
            calendar.timegm(p1.last_modified.timetuple()) <= 1)
        self.assertTrue(
            calendar.timegm(s2["last_modified"].timetuple()) -
            calendar.timegm(p2.last_modified.timetuple()) <= 1)

    def test_multiple_packages_same_version(self):
        """ Can upload multiple packages that have the same version """
        with patch.object(self.db, "allow_overwrite", False):
            name, version = "a", "1"
            path1 = "old_package_path-1.tar.gz"
            self.db.upload(path1, BytesIO(b"test1234"), name, version)
            path2 = "new_path-1.whl"
            self.db.upload(path2, BytesIO(b"test1234"), name, version)

            all_versions = self.db.all(name)
            self.assertEqual(len(all_versions), 2)

    def test_reload_if_needed(self):
        """ Reload the cache if it's empty """
        self.db.storage = MagicMock()
        self.db.storage.list.return_value = [make_package(factory=SQLPackage)]
        self.db.reload_if_needed()
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)

    def test_check_health_success(self):
        """ check_health returns True for good connection """
        ok, msg = self.db.check_health()
        self.assertTrue(ok)

    def test_check_health_fail(self):
        """ check_health returns False for bad connection """
        dbmock = self.db.db = MagicMock()

        def throw(*_, **__):
            """ Throw an exception """
            raise SQLAlchemyError("DB exception")

        dbmock.query.side_effect = throw
        ok, msg = self.db.check_health()
        self.assertFalse(ok)
示例#4
0
class TestSQLiteCache(unittest.TestCase):
    """ Tests for the SQLAlchemy cache """

    DB_URL = 'sqlite://'

    @classmethod
    def setUpClass(cls):
        super(TestSQLiteCache, cls).setUpClass()
        settings = {
            'pypi.storage': 'tests.DummyStorage',
            'db.url': cls.DB_URL,
        }
        try:
            cls.kwargs = SQLCache.configure(settings)
        except OperationalError:
            raise unittest.SkipTest("Couldn't connect to database")

    def setUp(self):
        super(TestSQLiteCache, self).setUp()
        transaction.begin()
        self.request = DummyRequest()
        self.request.tm = transaction.manager
        self.db = SQLCache(self.request, **self.kwargs)
        self.sql = self.db.db
        self.storage = self.db.storage = MagicMock(spec=IStorage)

    def tearDown(self):
        super(TestSQLiteCache, self).tearDown()
        transaction.abort()
        self.sql.query(SQLPackage).delete()
        transaction.commit()
        self.request._process_finished_callbacks()

    def test_upload(self):
        """ upload() saves package and uploads to storage """
        pkg = make_package(factory=SQLPackage)
        self.db.upload(pkg.filename, None, pkg.name, pkg.version)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
        saved_pkg = self.sql.query(SQLPackage).first()
        self.assertEqual(saved_pkg, pkg)
        self.storage.upload.assert_called_with(pkg, None)

    def test_upload_overwrite(self):
        """ Uploading a preexisting packages overwrites current package """
        self.db.allow_overwrite = True
        name, filename = 'a', 'a-1.tar.gz'
        self.db.upload(filename, 'old', name)
        self.db.upload(filename, 'new', name)

        all_versions = self.db.all(name)
        self.assertEqual(len(all_versions), 1)

    def test_save(self):
        """ save() puts object into database """
        pkg = make_package(factory=SQLPackage)
        self.db.save(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
        saved_pkg = self.sql.query(SQLPackage).first()
        self.assertEqual(saved_pkg, pkg)

    def test_save_unicode(self):
        """ save() can store packages with unicode in the names """
        pkg = make_package(u'mypackage™', factory=SQLPackage)
        self.db.save(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
        saved_pkg = self.sql.query(SQLPackage).first()
        self.assertEqual(saved_pkg, pkg)

    def test_delete(self):
        """ delete() removes object from database and deletes from storage """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        transaction.commit()
        self.sql.add(pkg)
        self.db.delete(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 0)
        self.storage.delete.assert_called_with(pkg)

    def test_clear(self):
        """ clear() removes object from database """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        transaction.commit()
        self.sql.add(pkg)
        self.db.delete(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 0)

    def test_reload(self):
        """ reload_from_storage() inserts packages into the database """
        keys = [
            make_package(factory=SQLPackage),
            make_package('mypkg2',
                         '1.3.4',
                         'my/other/path',
                         factory=SQLPackage),
        ]
        self.storage.list.return_value = keys
        self.db.reload_from_storage()
        all_pkgs = self.sql.query(SQLPackage).all()
        self.assertItemsEqual(all_pkgs, keys)

    def test_fetch(self):
        """ fetch() retrieves a package from the database """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        saved_pkg = self.db.fetch(pkg.filename)
        self.assertEqual(saved_pkg, pkg)

    def test_fetch_missing(self):
        """ fetch() returns None if no package exists """
        saved_pkg = self.db.fetch('missing_pkg-1.2.tar.gz')
        self.assertIsNone(saved_pkg)

    def test_all_versions(self):
        """ all() returns all versions of a package """
        pkgs = [
            make_package(factory=SQLPackage),
            make_package(version='1.3', filename='mypath3',
                         factory=SQLPackage),
            make_package('mypkg2',
                         '1.3.4',
                         'my/other/path',
                         factory=SQLPackage),
        ]
        self.sql.add_all(pkgs)
        saved_pkgs = self.db.all('mypkg')
        self.assertItemsEqual(saved_pkgs, pkgs[:2])

    def test_distinct(self):
        """ distinct() returns all unique package names """
        pkgs = [
            make_package(factory=SQLPackage),
            make_package(version='1.3', filename='mypath3',
                         factory=SQLPackage),
            make_package('mypkg2',
                         '1.3.4',
                         'my/other/path',
                         factory=SQLPackage),
        ]
        self.sql.add_all(pkgs)
        saved_pkgs = self.db.distinct()
        self.assertItemsEqual(saved_pkgs, set([p.name for p in pkgs]))

    def test_search_or(self):
        """ search() returns packages that match the query """
        pkgs = [
            make_package(factory=SQLPackage),
            make_package('somepackage',
                         version='1.3',
                         filename='mypath3',
                         summary='this is mypkg',
                         factory=SQLPackage),
            make_package('mypkg2',
                         '1.3.4',
                         'my/other/path',
                         factory=SQLPackage),
            make_package('package', factory=SQLPackage),
        ]
        self.sql.add_all(pkgs)
        criteria = {'name': ['mypkg'], 'summary': ['mypkg']}
        packages = self.db.search(criteria, 'or')
        self.assertItemsEqual(packages, pkgs[:-1])

    def test_search_and(self):
        """ search() returns packages that match the query """
        pkgs = [
            make_package(factory=SQLPackage),
            make_package('somepackage',
                         version='1.3',
                         filename='mypath3',
                         summary='this is mypkg',
                         factory=SQLPackage),
            make_package('mypkg2',
                         '1.3.4',
                         'my/other/path',
                         factory=SQLPackage),
            make_package('package', factory=SQLPackage),
        ]
        self.sql.add_all(pkgs)
        criteria = {'name': ['my', 'pkg'], 'summary': ['this', 'mypkg']}
        packages = self.db.search(criteria, 'and')
        self.assertItemsEqual(packages, pkgs[:-1])

    def test_summary(self):
        """ summary constructs per-package metadata summary """
        self.db.upload('pkg1-0.3.tar.gz', None, 'pkg1', '0.3')
        self.db.upload('pkg1-1.1.tar.gz', None, 'pkg1', '1.1')
        p1 = self.db.upload('pkg1a2.tar.gz', None, 'pkg1', '1.1.1a2')
        p2 = self.db.upload('pkg2.tar.gz', None, 'pkg2', '0.1dev2')
        s1, s2 = self.db.summary()  # pylint: disable=E0632
        # Order them correctly. assertItemsEqual isn't playing nice in py2.6
        if s1['name'] == 'pkg2':
            s1, s2 = s2, s1
        # last_modified may be rounded when stored in MySQL,
        # so the best we can do is make sure they're close.
        self.assertTrue(
            calendar.timegm(s1['last_modified'].timetuple()) -
            calendar.timegm(p1.last_modified.timetuple()) <= 1)
        self.assertTrue(
            calendar.timegm(s2['last_modified'].timetuple()) -
            calendar.timegm(p2.last_modified.timetuple()) <= 1)

    def test_multiple_packages_same_version(self):
        """ Can upload multiple packages that have the same version """
        with patch.object(self.db, 'allow_overwrite', False):
            name, version = 'a', '1'
            path1 = 'old_package_path-1.tar.gz'
            self.db.upload(path1, None, name, version)
            path2 = 'new_path-1.whl'
            self.db.upload(path2, None, name, version)

            all_versions = self.db.all(name)
            self.assertEqual(len(all_versions), 2)

    def test_reload_if_needed(self):
        """ Reload the cache if it's empty """
        self.db.storage = MagicMock()
        self.db.storage.list.return_value = [make_package(factory=SQLPackage)]
        self.db.reload_if_needed()
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
示例#5
0
class TestSQLCache(unittest.TestCase):
    """ Tests for the SQLAlchemy cache """
    @classmethod
    def setUpClass(cls):
        super(TestSQLCache, cls).setUpClass()
        settings = {
            'pypi.storage': 'tests.DummyStorage',
            'db.url': 'sqlite:///:memory:',
        }
        cls.kwargs = SQLCache.configure(settings)

    def setUp(self):
        super(TestSQLCache, self).setUp()
        self.request = DummyRequest()
        self.db = SQLCache(self.request, **self.kwargs)
        self.sql = self.db.db
        self.storage = self.db.storage = MagicMock(spec=IStorage)

    def tearDown(self):
        super(TestSQLCache, self).tearDown()
        transaction.abort()
        self.sql.query(SQLPackage).delete()
        transaction.commit()
        self.request._process_finished_callbacks()

    def test_upload(self):
        """ upload() saves package and uploads to storage """
        pkg = make_package(factory=SQLPackage)
        self.db.upload(pkg.filename, None, pkg.name, pkg.version)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
        saved_pkg = self.sql.query(SQLPackage).first()
        self.assertEqual(saved_pkg, pkg)
        self.storage.upload.assert_called_with(pkg, None)

    def test_save(self):
        """ save() puts object into database """
        pkg = make_package(factory=SQLPackage)
        self.db.save(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
        saved_pkg = self.sql.query(SQLPackage).first()
        self.assertEqual(saved_pkg, pkg)

    def test_delete(self):
        """ delete() removes object from database and deletes from storage """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        transaction.commit()
        self.sql.add(pkg)
        self.db.delete(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 0)
        self.storage.delete.assert_called_with(pkg)

    def test_clear(self):
        """ clear() removes object from database """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        transaction.commit()
        self.sql.add(pkg)
        self.db.delete(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 0)

    def test_reload(self):
        """ reload_from_storage() inserts packages into the database """
        keys = [
            make_package(factory=SQLPackage),
            make_package('mypkg2',
                         '1.3.4',
                         'my/other/path',
                         factory=SQLPackage),
        ]
        self.storage.list.return_value = keys
        self.db.reload_from_storage()
        all_pkgs = self.sql.query(SQLPackage).all()
        self.assertItemsEqual(all_pkgs, keys)

    def test_fetch(self):
        """ fetch() retrieves a package from the database """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        saved_pkg = self.db.fetch(pkg.filename)
        self.assertEqual(saved_pkg, pkg)

    def test_fetch_missing(self):
        """ fetch() returns None if no package exists """
        saved_pkg = self.db.fetch('missing_pkg-1.2.tar.gz')
        self.assertIsNone(saved_pkg)

    def test_all_versions(self):
        """ all() returns all versions of a package """
        pkgs = [
            make_package(factory=SQLPackage),
            make_package(version='1.3', filename='mypath3',
                         factory=SQLPackage),
            make_package('mypkg2',
                         '1.3.4',
                         'my/other/path',
                         factory=SQLPackage),
        ]
        self.sql.add_all(pkgs)
        saved_pkgs = self.db.all('mypkg')
        self.assertItemsEqual(saved_pkgs, pkgs[:2])

    def test_distinct(self):
        """ distinct() returns all unique package names """
        pkgs = [
            make_package(factory=SQLPackage),
            make_package(version='1.3', filename='mypath3',
                         factory=SQLPackage),
            make_package('mypkg2',
                         '1.3.4',
                         'my/other/path',
                         factory=SQLPackage),
        ]
        self.sql.add_all(pkgs)
        saved_pkgs = self.db.distinct()
        self.assertItemsEqual(saved_pkgs, set([p.name for p in pkgs]))

    def test_summary(self):
        """ summary constructs per-package metadata summary """
        self.db.upload('pkg1-0.3.tar.gz', None, 'pkg1', '0.3')
        self.db.upload('pkg1-1.1.tar.gz', None, 'pkg1', '1.1')
        p1 = self.db.upload('pkg1a2.tar.gz', None, 'pkg1', '1.1.1a2')
        p2 = self.db.upload('pkg2.tar.gz', None, 'pkg2', '0.1dev2')
        summaries = self.db.summary()
        self.assertItemsEqual(summaries, [
            {
                'name': 'pkg1',
                'stable': '1.1',
                'unstable': '1.1.1a2',
                'last_modified': p1.last_modified,
            },
            {
                'name': 'pkg2',
                'stable': None,
                'unstable': '0.1dev2',
                'last_modified': p2.last_modified,
            },
        ])

    def test_multiple_packages_same_version(self):
        """ Can upload multiple packages that have the same version """
        with patch.object(self.db, 'allow_overwrite', False):
            name, version = 'a', '1'
            path1 = 'old_package_path-1.tar.gz'
            self.db.upload(path1, None, name, version)
            path2 = 'new_path-1.whl'
            self.db.upload(path2, None, name, version)

            all_versions = self.db.all(name)
            self.assertEqual(len(all_versions), 2)

    def test_reload_if_needed(self):
        """ Reload the cache if it's empty """
        self.db.storage = MagicMock()
        self.db.storage.list.return_value = [make_package(factory=SQLPackage)]
        self.db.reload_if_needed()
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
示例#6
0
class TestSQLCache(unittest.TestCase):

    """ Tests for the SQLAlchemy cache """

    @classmethod
    def setUpClass(cls):
        super(TestSQLCache, cls).setUpClass()
        settings = {"pypi.storage": "tests.DummyStorage", "db.url": "sqlite:///:memory:"}
        cls.kwargs = SQLCache.configure(settings)

    def setUp(self):
        super(TestSQLCache, self).setUp()
        self.request = DummyRequest()
        self.db = SQLCache(self.request, **self.kwargs)
        self.sql = self.db.db
        self.storage = self.db.storage = MagicMock(spec=IStorage)

    def tearDown(self):
        super(TestSQLCache, self).tearDown()
        transaction.abort()
        self.sql.query(SQLPackage).delete()
        transaction.commit()
        self.request._process_finished_callbacks()

    def test_upload(self):
        """ upload() saves package and uploads to storage """
        pkg = make_package(factory=SQLPackage)
        self.db.upload(pkg.filename, None, pkg.name, pkg.version)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
        saved_pkg = self.sql.query(SQLPackage).first()
        self.assertEqual(saved_pkg, pkg)
        self.storage.upload.assert_called_with(pkg, None)

    def test_save(self):
        """ save() puts object into database """
        pkg = make_package(factory=SQLPackage)
        self.db.save(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
        saved_pkg = self.sql.query(SQLPackage).first()
        self.assertEqual(saved_pkg, pkg)

    def test_delete(self):
        """ delete() removes object from database and deletes from storage """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        transaction.commit()
        self.sql.add(pkg)
        self.db.delete(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 0)
        self.storage.delete.assert_called_with(pkg)

    def test_clear(self):
        """ clear() removes object from database """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        transaction.commit()
        self.sql.add(pkg)
        self.db.delete(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 0)

    def test_reload(self):
        """ reload_from_storage() inserts packages into the database """
        keys = [make_package(factory=SQLPackage), make_package("mypkg2", "1.3.4", "my/other/path", factory=SQLPackage)]
        self.storage.list.return_value = keys
        self.db.reload_from_storage()
        all_pkgs = self.sql.query(SQLPackage).all()
        self.assertItemsEqual(all_pkgs, keys)

    def test_fetch(self):
        """ fetch() retrieves a package from the database """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        saved_pkg = self.db.fetch(pkg.filename)
        self.assertEqual(saved_pkg, pkg)

    def test_fetch_missing(self):
        """ fetch() returns None if no package exists """
        saved_pkg = self.db.fetch("missing_pkg-1.2.tar.gz")
        self.assertIsNone(saved_pkg)

    def test_all_versions(self):
        """ all() returns all versions of a package """
        pkgs = [
            make_package(factory=SQLPackage),
            make_package(version="1.3", filename="mypath3", factory=SQLPackage),
            make_package("mypkg2", "1.3.4", "my/other/path", factory=SQLPackage),
        ]
        self.sql.add_all(pkgs)
        saved_pkgs = self.db.all("mypkg")
        self.assertItemsEqual(saved_pkgs, pkgs[:2])

    def test_distinct(self):
        """ distinct() returns all unique package names """
        pkgs = [
            make_package(factory=SQLPackage),
            make_package(version="1.3", filename="mypath3", factory=SQLPackage),
            make_package("mypkg2", "1.3.4", "my/other/path", factory=SQLPackage),
        ]
        self.sql.add_all(pkgs)
        saved_pkgs = self.db.distinct()
        self.assertItemsEqual(saved_pkgs, set([p.name for p in pkgs]))

    def test_summary(self):
        """ summary constructs per-package metadata summary """
        self.db.upload("pkg1-0.3.tar.gz", None, "pkg1", "0.3")
        self.db.upload("pkg1-1.1.tar.gz", None, "pkg1", "1.1")
        p1 = self.db.upload("pkg1a2.tar.gz", None, "pkg1", "1.1.1a2")
        p2 = self.db.upload("pkg2.tar.gz", None, "pkg2", "0.1dev2")
        summaries = self.db.summary()
        self.assertItemsEqual(
            summaries,
            [
                {"name": "pkg1", "stable": "1.1", "unstable": "1.1.1a2", "last_modified": p1.last_modified},
                {"name": "pkg2", "stable": None, "unstable": "0.1dev2", "last_modified": p2.last_modified},
            ],
        )

    def test_multiple_packages_same_version(self):
        """ Can upload multiple packages that have the same version """
        with patch.object(self.db, "allow_overwrite", False):
            name, version = "a", "1"
            path1 = "old_package_path-1.tar.gz"
            self.db.upload(path1, None, name, version)
            path2 = "new_path-1.whl"
            self.db.upload(path2, None, name, version)

            all_versions = self.db.all(name)
            self.assertEqual(len(all_versions), 2)

    def test_reload_if_needed(self):
        """ Reload the cache if it's empty """
        self.db.storage = MagicMock()
        self.db.storage.list.return_value = [make_package(factory=SQLPackage)]
        self.db.reload_if_needed()
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
示例#7
0
class TestSQLiteCache(unittest.TestCase):

    """ Tests for the SQLAlchemy cache """

    DB_URL = "sqlite://"

    @classmethod
    def setUpClass(cls):
        super(TestSQLiteCache, cls).setUpClass()
        settings = {"pypi.storage": "tests.DummyStorage", "db.url": cls.DB_URL}
        try:
            cls.kwargs = SQLCache.configure(settings)
        except OperationalError:
            raise unittest.SkipTest("Couldn't connect to database")

    def setUp(self):
        super(TestSQLiteCache, self).setUp()
        transaction.begin()
        self.request = DummyRequest()
        self.request.tm = transaction.manager
        self.db = SQLCache(self.request, **self.kwargs)
        self.sql = self.db.db
        self.storage = self.db.storage = MagicMock(spec=IStorage)

    def tearDown(self):
        super(TestSQLiteCache, self).tearDown()
        transaction.abort()
        self.sql.query(SQLPackage).delete()
        transaction.commit()
        self.request._process_finished_callbacks()

    def test_upload(self):
        """ upload() saves package and uploads to storage """
        pkg = make_package(factory=SQLPackage)
        self.db.upload(pkg.filename, None, pkg.name, pkg.version)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
        saved_pkg = self.sql.query(SQLPackage).first()
        self.assertEqual(saved_pkg, pkg)
        self.storage.upload.assert_called_with(pkg, None)

    def test_upload_overwrite(self):
        """ Uploading a preexisting packages overwrites current package """
        self.db.allow_overwrite = True
        name, filename = "a", "a-1.tar.gz"
        self.db.upload(filename, "old", name)
        self.db.upload(filename, "new", name)

        all_versions = self.db.all(name)
        self.assertEqual(len(all_versions), 1)

    def test_save(self):
        """ save() puts object into database """
        pkg = make_package(factory=SQLPackage)
        self.db.save(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
        saved_pkg = self.sql.query(SQLPackage).first()
        self.assertEqual(saved_pkg, pkg)

    def test_save_unicode(self):
        """ save() can store packages with unicode in the names """
        pkg = make_package("mypackage™", factory=SQLPackage)
        self.db.save(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
        saved_pkg = self.sql.query(SQLPackage).first()
        self.assertEqual(saved_pkg, pkg)

    def test_delete(self):
        """ delete() removes object from database and deletes from storage """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        transaction.commit()
        self.sql.add(pkg)
        self.db.delete(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 0)
        self.storage.delete.assert_called_with(pkg)

    def test_clear(self):
        """ clear() removes object from database """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        transaction.commit()
        self.sql.add(pkg)
        self.db.delete(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 0)

    def test_reload(self):
        """ reload_from_storage() inserts packages into the database """
        keys = [
            make_package(factory=SQLPackage),
            make_package("mypkg2", "1.3.4", "my/other/path", factory=SQLPackage),
        ]
        self.storage.list.return_value = keys
        self.db.reload_from_storage()
        all_pkgs = self.sql.query(SQLPackage).all()
        self.assertItemsEqual(all_pkgs, keys)

    def test_fetch(self):
        """ fetch() retrieves a package from the database """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        saved_pkg = self.db.fetch(pkg.filename)
        self.assertEqual(saved_pkg, pkg)

    def test_fetch_missing(self):
        """ fetch() returns None if no package exists """
        saved_pkg = self.db.fetch("missing_pkg-1.2.tar.gz")
        self.assertIsNone(saved_pkg)

    def test_all_versions(self):
        """ all() returns all versions of a package """
        pkgs = [
            make_package(factory=SQLPackage),
            make_package(version="1.3", filename="mypath3", factory=SQLPackage),
            make_package("mypkg2", "1.3.4", "my/other/path", factory=SQLPackage),
        ]
        self.sql.add_all(pkgs)
        saved_pkgs = self.db.all("mypkg")
        self.assertItemsEqual(saved_pkgs, pkgs[:2])

    def test_distinct(self):
        """ distinct() returns all unique package names """
        pkgs = [
            make_package(factory=SQLPackage),
            make_package(version="1.3", filename="mypath3", factory=SQLPackage),
            make_package("mypkg2", "1.3.4", "my/other/path", factory=SQLPackage),
        ]
        self.sql.add_all(pkgs)
        saved_pkgs = self.db.distinct()
        self.assertItemsEqual(saved_pkgs, set([p.name for p in pkgs]))

    def test_search_or(self):
        """ search() returns packages that match the query """
        pkgs = [
            make_package(factory=SQLPackage),
            make_package(
                "somepackage",
                version="1.3",
                filename="mypath3",
                summary="this is mypkg",
                factory=SQLPackage,
            ),
            make_package("mypkg2", "1.3.4", "my/other/path", factory=SQLPackage),
            make_package("package", factory=SQLPackage),
        ]
        self.sql.add_all(pkgs)
        criteria = {"name": ["mypkg"], "summary": ["mypkg"]}
        packages = self.db.search(criteria, "or")
        self.assertItemsEqual(packages, pkgs[:-1])

    def test_search_and(self):
        """ search() returns packages that match the query """
        pkgs = [
            make_package(factory=SQLPackage),
            make_package(
                "somepackage",
                version="1.3",
                filename="mypath3",
                summary="this is mypkg",
                factory=SQLPackage,
            ),
            make_package("mypkg2", "1.3.4", "my/other/path", factory=SQLPackage),
            make_package("package", factory=SQLPackage),
        ]
        self.sql.add_all(pkgs)
        criteria = {"name": ["my", "pkg"], "summary": ["this", "mypkg"]}
        packages = self.db.search(criteria, "and")
        self.assertItemsEqual(packages, pkgs[:-1])

    def test_summary(self):
        """ summary constructs per-package metadata summary """
        self.db.upload("pkg1-0.3.tar.gz", None, "pkg1", "0.3")
        self.db.upload("pkg1-1.1.tar.gz", None, "pkg1", "1.1")
        p1 = self.db.upload("pkg1a2.tar.gz", None, "pkg1", "1.1.1a2")
        p2 = self.db.upload("pkg2.tar.gz", None, "pkg2", "0.1dev2")
        s1, s2 = self.db.summary()  # pylint: disable=E0632
        # Order them correctly. assertItemsEqual isn't playing nice in py2.6
        if s1["name"] == "pkg2":
            s1, s2 = s2, s1
        # last_modified may be rounded when stored in MySQL,
        # so the best we can do is make sure they're close.
        self.assertTrue(
            calendar.timegm(s1["last_modified"].timetuple())
            - calendar.timegm(p1.last_modified.timetuple())
            <= 1
        )
        self.assertTrue(
            calendar.timegm(s2["last_modified"].timetuple())
            - calendar.timegm(p2.last_modified.timetuple())
            <= 1
        )

    def test_multiple_packages_same_version(self):
        """ Can upload multiple packages that have the same version """
        with patch.object(self.db, "allow_overwrite", False):
            name, version = "a", "1"
            path1 = "old_package_path-1.tar.gz"
            self.db.upload(path1, None, name, version)
            path2 = "new_path-1.whl"
            self.db.upload(path2, None, name, version)

            all_versions = self.db.all(name)
            self.assertEqual(len(all_versions), 2)

    def test_reload_if_needed(self):
        """ Reload the cache if it's empty """
        self.db.storage = MagicMock()
        self.db.storage.list.return_value = [make_package(factory=SQLPackage)]
        self.db.reload_if_needed()
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)

    def test_check_health_success(self):
        """ check_health returns True for good connection """
        ok, msg = self.db.check_health()
        self.assertTrue(ok)

    def test_check_health_fail(self):
        """ check_health returns False for bad connection """
        dbmock = self.db.db = MagicMock()

        def throw(*_, **__):
            """ Throw an exception """
            raise SQLAlchemyError("DB exception")

        dbmock.query.side_effect = throw
        ok, msg = self.db.check_health()
        self.assertFalse(ok)
示例#8
0
class TestSQLiteCache(unittest.TestCase):

    """ Tests for the SQLAlchemy cache """

    DB_URL = 'sqlite:///:memory:'

    @classmethod
    def setUpClass(cls):
        super(TestSQLiteCache, cls).setUpClass()
        settings = {
            'pypi.storage': 'tests.DummyStorage',
            'db.url': cls.DB_URL,
        }
        try:
            cls.kwargs = SQLCache.configure(settings)
        except OperationalError:
            raise unittest.SkipTest("Couldn't connect to database")

    def setUp(self):
        super(TestSQLiteCache, self).setUp()
        self.request = DummyRequest()
        self.db = SQLCache(self.request, **self.kwargs)
        self.sql = self.db.db
        self.storage = self.db.storage = MagicMock(spec=IStorage)

    def tearDown(self):
        super(TestSQLiteCache, self).tearDown()
        transaction.abort()
        self.sql.query(SQLPackage).delete()
        transaction.commit()
        self.request._process_finished_callbacks()

    def test_upload(self):
        """ upload() saves package and uploads to storage """
        pkg = make_package(factory=SQLPackage)
        self.db.upload(pkg.filename, None, pkg.name, pkg.version)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
        saved_pkg = self.sql.query(SQLPackage).first()
        self.assertEqual(saved_pkg, pkg)
        self.storage.upload.assert_called_with(pkg, None)

    def test_upload_overwrite(self):
        """ Uploading a preexisting packages overwrites current package """
        self.db.allow_overwrite = True
        name, filename = 'a', 'a-1.tar.gz'
        self.db.upload(filename, 'old', name)
        self.db.upload(filename, 'new', name)

        all_versions = self.db.all(name)
        self.assertEqual(len(all_versions), 1)

    def test_save(self):
        """ save() puts object into database """
        pkg = make_package(factory=SQLPackage)
        self.db.save(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
        saved_pkg = self.sql.query(SQLPackage).first()
        self.assertEqual(saved_pkg, pkg)

    def test_save_unicode(self):
        """ save() can store packages with unicode in the names """
        pkg = make_package(u'mypackage™', factory=SQLPackage)
        self.db.save(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
        saved_pkg = self.sql.query(SQLPackage).first()
        self.assertEqual(saved_pkg, pkg)

    def test_delete(self):
        """ delete() removes object from database and deletes from storage """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        transaction.commit()
        self.sql.add(pkg)
        self.db.delete(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 0)
        self.storage.delete.assert_called_with(pkg)

    def test_clear(self):
        """ clear() removes object from database """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        transaction.commit()
        self.sql.add(pkg)
        self.db.delete(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 0)

    def test_reload(self):
        """ reload_from_storage() inserts packages into the database """
        keys = [
            make_package(factory=SQLPackage),
            make_package('mypkg2', '1.3.4', 'my/other/path',
                         factory=SQLPackage),
        ]
        self.storage.list.return_value = keys
        self.db.reload_from_storage()
        all_pkgs = self.sql.query(SQLPackage).all()
        self.assertItemsEqual(all_pkgs, keys)

    def test_fetch(self):
        """ fetch() retrieves a package from the database """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        saved_pkg = self.db.fetch(pkg.filename)
        self.assertEqual(saved_pkg, pkg)

    def test_fetch_missing(self):
        """ fetch() returns None if no package exists """
        saved_pkg = self.db.fetch('missing_pkg-1.2.tar.gz')
        self.assertIsNone(saved_pkg)

    def test_all_versions(self):
        """ all() returns all versions of a package """
        pkgs = [
            make_package(factory=SQLPackage),
            make_package(version='1.3', filename='mypath3',
                         factory=SQLPackage),
            make_package('mypkg2', '1.3.4', 'my/other/path',
                         factory=SQLPackage),
        ]
        self.sql.add_all(pkgs)
        saved_pkgs = self.db.all('mypkg')
        self.assertItemsEqual(saved_pkgs, pkgs[:2])

    def test_distinct(self):
        """ distinct() returns all unique package names """
        pkgs = [
            make_package(factory=SQLPackage),
            make_package(version='1.3', filename='mypath3',
                         factory=SQLPackage),
            make_package('mypkg2', '1.3.4', 'my/other/path',
                         factory=SQLPackage),
        ]
        self.sql.add_all(pkgs)
        saved_pkgs = self.db.distinct()
        self.assertItemsEqual(saved_pkgs, set([p.name for p in pkgs]))

    def test_summary(self):
        """ summary constructs per-package metadata summary """
        self.db.upload('pkg1-0.3.tar.gz', None, 'pkg1', '0.3')
        self.db.upload('pkg1-1.1.tar.gz', None, 'pkg1', '1.1')
        p1 = self.db.upload('pkg1a2.tar.gz', None, 'pkg1', '1.1.1a2')
        p2 = self.db.upload('pkg2.tar.gz', None, 'pkg2', '0.1dev2')
        s1, s2 = self.db.summary()
        # Order them correctly. assertItemsEqual isn't playing nice in py2.6
        if s1['name'] == 'pkg2':
            s1, s2 = s2, s1
        self.assertEqual(s1['stable'], u'1.1')
        self.assertEqual(s1['unstable'], u'1.1.1a2')
        self.assertIsNone(s2['stable'])
        self.assertEqual(s2['unstable'], u'0.1dev2')
        # last_modified may be rounded when stored in MySQL,
        # so the best we can do is make sure they're close.
        self.assertTrue(
            calendar.timegm(s1['last_modified'].timetuple()) -
            calendar.timegm(p1.last_modified.timetuple()) <= 1)
        self.assertTrue(
            calendar.timegm(s2['last_modified'].timetuple()) -
            calendar.timegm(p2.last_modified.timetuple()) <= 1)

    def test_multiple_packages_same_version(self):
        """ Can upload multiple packages that have the same version """
        with patch.object(self.db, 'allow_overwrite', False):
            name, version = 'a', '1'
            path1 = 'old_package_path-1.tar.gz'
            self.db.upload(path1, None, name, version)
            path2 = 'new_path-1.whl'
            self.db.upload(path2, None, name, version)

            all_versions = self.db.all(name)
            self.assertEqual(len(all_versions), 2)

    def test_reload_if_needed(self):
        """ Reload the cache if it's empty """
        self.db.storage = MagicMock()
        self.db.storage.list.return_value = [
            make_package(factory=SQLPackage)
        ]
        self.db.reload_if_needed()
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
示例#9
0
class TestSQLCache(unittest.TestCase):

    """ Tests for the SQLAlchemy cache """

    @classmethod
    def setUpClass(cls):
        super(TestSQLCache, cls).setUpClass()
        settings = {
            'pypi.storage': 'tests.DummyStorage',
            'db.url': 'sqlite:///:memory:',
        }
        cls.kwargs = SQLCache.configure(settings)

    def setUp(self):
        super(TestSQLCache, self).setUp()
        self.request = DummyRequest()
        self.db = SQLCache(self.request, **self.kwargs)
        self.sql = self.db.db
        self.storage = self.db.storage = MagicMock(spec=IStorage)

    def tearDown(self):
        super(TestSQLCache, self).tearDown()
        transaction.abort()
        self.sql.query(SQLPackage).delete()
        transaction.commit()
        self.request._process_finished_callbacks()

    def test_upload(self):
        """ upload() saves package and uploads to storage """
        pkg = make_package(factory=SQLPackage)
        self.db.upload(pkg.filename, None, pkg.name, pkg.version)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
        saved_pkg = self.sql.query(SQLPackage).first()
        self.assertEqual(saved_pkg, pkg)
        self.storage.upload.assert_called_with(pkg, None)

    def test_upload_overwrite(self):
        """ Uploading a preexisting packages overwrites current package """
        self.db.allow_overwrite = True
        name, filename = 'a', 'a-1.tar.gz'
        self.db.upload(filename, 'old', name)
        self.db.upload(filename, 'new', name)

        all_versions = self.db.all(name)
        self.assertEqual(len(all_versions), 1)

    def test_save(self):
        """ save() puts object into database """
        pkg = make_package(factory=SQLPackage)
        self.db.save(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)
        saved_pkg = self.sql.query(SQLPackage).first()
        self.assertEqual(saved_pkg, pkg)

    def test_delete(self):
        """ delete() removes object from database and deletes from storage """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        transaction.commit()
        self.sql.add(pkg)
        self.db.delete(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 0)
        self.storage.delete.assert_called_with(pkg)

    def test_clear(self):
        """ clear() removes object from database """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        transaction.commit()
        self.sql.add(pkg)
        self.db.delete(pkg)
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 0)

    def test_reload(self):
        """ reload_from_storage() inserts packages into the database """
        keys = [
            make_package(factory=SQLPackage),
            make_package('mypkg2', '1.3.4', 'my/other/path',
                         factory=SQLPackage),
        ]
        self.storage.list.return_value = keys
        self.db.reload_from_storage()
        all_pkgs = self.sql.query(SQLPackage).all()
        self.assertItemsEqual(all_pkgs, keys)

    def test_fetch(self):
        """ fetch() retrieves a package from the database """
        pkg = make_package(factory=SQLPackage)
        self.sql.add(pkg)
        saved_pkg = self.db.fetch(pkg.filename)
        self.assertEqual(saved_pkg, pkg)

    def test_fetch_missing(self):
        """ fetch() returns None if no package exists """
        saved_pkg = self.db.fetch('missing_pkg-1.2.tar.gz')
        self.assertIsNone(saved_pkg)

    def test_all_versions(self):
        """ all() returns all versions of a package """
        pkgs = [
            make_package(factory=SQLPackage),
            make_package(version='1.3', filename='mypath3',
                         factory=SQLPackage),
            make_package('mypkg2', '1.3.4', 'my/other/path',
                         factory=SQLPackage),
        ]
        self.sql.add_all(pkgs)
        saved_pkgs = self.db.all('mypkg')
        self.assertItemsEqual(saved_pkgs, pkgs[:2])

    def test_distinct(self):
        """ distinct() returns all unique package names """
        pkgs = [
            make_package(factory=SQLPackage),
            make_package(version='1.3', filename='mypath3',
                         factory=SQLPackage),
            make_package('mypkg2', '1.3.4', 'my/other/path',
                         factory=SQLPackage),
        ]
        self.sql.add_all(pkgs)
        saved_pkgs = self.db.distinct()
        self.assertItemsEqual(saved_pkgs, set([p.name for p in pkgs]))

    def test_summary(self):
        """ summary constructs per-package metadata summary """
        self.db.upload('pkg1-0.3.tar.gz', None, 'pkg1', '0.3')
        self.db.upload('pkg1-1.1.tar.gz', None, 'pkg1', '1.1')
        p1 = self.db.upload('pkg1a2.tar.gz', None, 'pkg1', '1.1.1a2')
        p2 = self.db.upload('pkg2.tar.gz', None, 'pkg2', '0.1dev2')
        summaries = self.db.summary()
        self.assertItemsEqual(summaries, [
            {
                'name': 'pkg1',
                'stable': '1.1',
                'unstable': '1.1.1a2',
                'last_modified': p1.last_modified,
            },
            {
                'name': 'pkg2',
                'stable': None,
                'unstable': '0.1dev2',
                'last_modified': p2.last_modified,
            },
        ])

    def test_multiple_packages_same_version(self):
        """ Can upload multiple packages that have the same version """
        with patch.object(self.db, 'allow_overwrite', False):
            name, version = 'a', '1'
            path1 = 'old_package_path-1.tar.gz'
            self.db.upload(path1, None, name, version)
            path2 = 'new_path-1.whl'
            self.db.upload(path2, None, name, version)

            all_versions = self.db.all(name)
            self.assertEqual(len(all_versions), 2)

    def test_reload_if_needed(self):
        """ Reload the cache if it's empty """
        self.db.storage = MagicMock()
        self.db.storage.list.return_value = [
            make_package(factory=SQLPackage)
        ]
        self.db.reload_if_needed()
        count = self.sql.query(SQLPackage).count()
        self.assertEqual(count, 1)