def test_unload_extensions_order(self): tdir = tempfile.mkdtemp() try: from pgxnclient.zip import unpack dir = unpack(get_test_filename('foobar-0.42.1.zip'), tdir) shutil.copyfile(get_test_filename('META-manyext.json'), os.path.join(dir, 'META.json')) from pgxnclient.cli import main main(['unload', '--yes', dir]) finally: shutil.rmtree(tdir) self.assertEquals(self.mock_popen.call_count, 4) self.assert_('psql' in self.mock_popen.call_args[0][0][0]) communicate = self.mock_popen.return_value.communicate self.assertEquals(communicate.call_args_list[0][0][0], b('DROP EXTENSION qux;')) self.assertEquals(communicate.call_args_list[1][0][0], b('DROP EXTENSION baz;')) self.assertEquals(communicate.call_args_list[2][0][0], b('DROP EXTENSION bar;')) self.assertEquals(communicate.call_args_list[3][0][0], b('DROP EXTENSION foo;'))
def test_check_psql_options(self, mock_get, mock_popen, mock_pgver, mock_isext): mock_get.side_effect = fake_get_file pop = mock_popen.return_value pop.returncode = 0 pop.communicate.return_value = (b(''), b('')) mock_pgver.return_value = (9,1,0) mock_isext.return_value = True from pgxnclient.cli import main main(['load', '--yes', '--dbname', 'dbdb', 'foobar']) args = mock_popen.call_args[0][0] self.assertEqual('dbdb', args[args.index('--dbname') + 1]) main(['load', '--yes', '-U', 'meme', 'foobar']) args = mock_popen.call_args[0][0] self.assertEqual('meme', args[args.index('--username') + 1]) main(['load', '--yes', '--port', '666', 'foobar']) args = mock_popen.call_args[0][0] self.assertEqual('666', args[args.index('--port') + 1]) main(['load', '--yes', '-h', 'somewhere', 'foobar']) args = mock_popen.call_args[0][0] self.assertEqual('somewhere', args[args.index('--host') + 1])
def test_unload_extensions_order(self): tdir = tempfile.mkdtemp() try: from pgxnclient.zip import unpack dir = unpack(get_test_filename('foobar-0.42.1.zip'), tdir) shutil.copyfile( get_test_filename('META-manyext.json'), os.path.join(dir, 'META.json')) from pgxnclient.cli import main main(['unload', '--yes', dir]) finally: shutil.rmtree(tdir) self.assertEquals(self.mock_popen.call_count, 4) self.assert_('psql' in self.mock_popen.call_args[0][0][0]) communicate = self.mock_popen.return_value.communicate self.assertEquals(communicate.call_args_list[0][0][0], b('DROP EXTENSION qux;')) self.assertEquals(communicate.call_args_list[1][0][0], b('DROP EXTENSION baz;')) self.assertEquals(communicate.call_args_list[2][0][0], b('DROP EXTENSION bar;')) self.assertEquals(communicate.call_args_list[3][0][0], b('DROP EXTENSION foo;'))
def setUp(self): self._p1 = patch('pgxnclient.commands.Popen') self.mock_popen = self._p1.start() self.mock_popen.return_value.returncode = 0 self.mock_popen.return_value.communicate.return_value = (b(''), b('')) self._p2 = patch('pgxnclient.commands.install.LoadUnload.is_extension') self.mock_isext = self._p2.start() self.mock_isext.return_value = True self._p3 = patch('pgxnclient.commands.install.LoadUnload.get_pg_version') self.mock_pgver = self._p3.start() self.mock_pgver.return_value = (9,1,0)
def setUp(self): self._p1 = patch('pgxnclient.commands.Popen') self.mock_popen = self._p1.start() self.mock_popen.return_value.returncode = 0 self.mock_popen.return_value.communicate.return_value = (b(''), b('')) self._p2 = patch('pgxnclient.commands.install.LoadUnload.is_extension') self.mock_isext = self._p2.start() self.mock_isext.return_value = True self._p3 = patch( 'pgxnclient.commands.install.LoadUnload.get_pg_version') self.mock_pgver = self._p3.start() self.mock_pgver.return_value = (9, 1, 0)
def test_info_case_insensitive(self): output = self._get_output(['info', '--versions', 'Foobar']) self.assertEqual(output, b("""\ foobar 0.43.2b1 testing foobar 0.42.1 stable foobar 0.42.0 stable """))
def test_info_op(self): output = self._get_output(['info', '--versions', 'foobar>0.42.0']) self.assertEqual( output, b("""\ foobar 0.43.2b1 testing foobar 0.42.1 stable """))
def test_info_case_insensitive(self): output = self._get_output(['info', '--versions', 'Foobar']) self.assertEqual( output, b("""\ foobar 0.43.2b1 testing foobar 0.42.1 stable foobar 0.42.0 stable """))
def test_info_op(self): output = self._get_output(["info", "--versions", "foobar>0.42.0"]) self.assertEqual( output, b( """\ foobar 0.43.2b1 testing foobar 0.42.1 stable """ ), )
def test_mirrors_list(self): output = self._get_output(['mirror']) self.assertEqual(output, b("""\ http://pgxn.depesz.com/ http://www.postgres-support.ch/pgxn/ http://pgxn.justatheory.com/ http://pgxn.darkixion.com/ http://mirrors.cat.pdx.edu/pgxn/ http://pgxn.dalibo.org/ http://pgxn.cxsoftware.org/ http://api.pgxn.org/ """))
def test_info_case_insensitive(self): output = self._get_output(["info", "--versions", "Foobar"]) self.assertEqual( output, b( """\ foobar 0.43.2b1 testing foobar 0.42.1 stable foobar 0.42.0 stable """ ), )
def test_load_local_tar(self, mock_get, mock_unpack): mock_get.side_effect = lambda *args: self.fail('network invoked') mock_unpack.side_effect = TarArchive.unpack_orig from pgxnclient.cli import main main(['load', '--yes', get_test_filename('foobar-0.42.1.tar.gz')]) self.assertEquals(mock_unpack.call_count, 0) self.assertEquals(self.mock_popen.call_count, 1) self.assert_('psql' in self.mock_popen.call_args[0][0][0]) communicate = self.mock_popen.return_value.communicate self.assertEquals(communicate.call_args[0][0], b('CREATE EXTENSION foobar;'))
def test_load_tar_url(self, mock_get, mock_unpack): mock_get.side_effect = fake_get_file mock_unpack.side_effect = TarArchive.unpack_orig from pgxnclient.cli import main main(['load', '--yes', 'http://example.org/foobar-0.42.1.tar.gz']) self.assertEquals(mock_unpack.call_count, 0) self.assertEquals(self.mock_popen.call_count, 1) self.assert_('psql' in self.mock_popen.call_args[0][0][0]) communicate = self.mock_popen.return_value.communicate self.assertEquals(communicate.call_args[0][0], b('CREATE EXTENSION foobar;'))
def unpack(zipname, destdir): logger.info(_("unpacking: %s"), zipname) destdir = os.path.abspath(destdir) zf = ZipFile(zipname, 'r') try: for fn in zf.namelist(): fname = os.path.abspath(os.path.join(destdir, fn)) if not fname.startswith(destdir): raise PgxnClientException( _("archive file '%s' trying to escape!") % fname) # Looks like checking for a trailing / is the only way to # tell if the file is a directory. if fn.endswith('/'): os.makedirs(fname) continue # The directory is not always explicitly present in the archive if not os.path.exists(os.path.dirname(fname)): os.makedirs(os.path.dirname(fname)) # Copy the file content logger.debug(_("saving: %s"), fname) fout = open(fname, "wb") try: data = zf.read(fn) # In order to restore the executable bit, I haven't find # anything that looks like an executable flag in the zipinfo, # so look at the hashbangs... isexec = data[:2] == b('#!') fout.write(data) finally: fout.close() if isexec: os.chmod(fname, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) finally: zf.close() # Choose the directory where to work. Because we are mostly a wrapper for # pgxs, let's look for a makefile. The zip should contain a single base # directory, so return the first dir we found containing a Makefile, # alternatively just return the unpacked dir for dir in os.listdir(destdir): for fn in ('Makefile', 'makefile', 'GNUmakefile', 'configure'): if os.path.exists(os.path.join(destdir, dir, fn)): return os.path.join(destdir, dir) return destdir
def test_mirrors_list(self): output = self._get_output(['mirror']) self.assertEqual( output, b("""\ http://pgxn.depesz.com/ http://www.postgres-support.ch/pgxn/ http://pgxn.justatheory.com/ http://pgxn.darkixion.com/ http://mirrors.cat.pdx.edu/pgxn/ http://pgxn.dalibo.org/ http://pgxn.cxsoftware.org/ http://api.pgxn.org/ """))
def test_mirror_info(self): output = self._get_output(['mirror', 'http://pgxn.justatheory.com/']) self.assertEqual(output, b("""\ uri: http://pgxn.justatheory.com/ frequency: daily location: Portland, OR, USA bandwidth: Cable organization: David E. Wheeler email: justatheory.com|pgxn timezone: America/Los_Angeles src: rsync://master.pgxn.org/pgxn/ rsync: notes: """))
def test_mirror_info(self): output = self._get_output(['mirror', 'http://pgxn.justatheory.com/']) self.assertEqual( output, b("""\ uri: http://pgxn.justatheory.com/ frequency: daily location: Portland, OR, USA bandwidth: Cable organization: David E. Wheeler email: justatheory.com|pgxn timezone: America/Los_Angeles src: rsync://master.pgxn.org/pgxn/ rsync: notes: """))
def unpack(self, destdir): zipname = self.filename logger.info(_("unpacking: %s"), zipname) destdir = os.path.abspath(destdir) self.open() try: for fn in self.list_files(): fname = os.path.abspath(os.path.join(destdir, fn)) if not fname.startswith(destdir): raise PgxnClientException( _("archive file '%s' trying to escape!") % fname) # Looks like checking for a trailing / is the only way to # tell if the file is a directory. if fn.endswith('/'): os.makedirs(fname) continue # The directory is not always explicitly present in the archive if not os.path.exists(os.path.dirname(fname)): os.makedirs(os.path.dirname(fname)) # Copy the file content logger.debug(_("saving: %s"), fname) fout = open(fname, "wb") try: data = self.read(fn) # In order to restore the executable bit, I haven't find # anything that looks like an executable flag in the zipinfo, # so look at the hashbangs... isexec = data[:2] == b('#!') fout.write(data) finally: fout.close() if isexec: os.chmod(fname, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) finally: self.close() return self._find_work_directory(destdir)
def test_load_local_dir(self, mock_get): mock_get.side_effect = lambda *args: self.fail('network invoked') tdir = tempfile.mkdtemp() try: from pgxnclient.zip import unpack dir = unpack(get_test_filename('foobar-0.42.1.zip'), tdir) from pgxnclient.cli import main main(['load', '--yes', dir]) finally: shutil.rmtree(tdir) self.assertEquals(self.mock_popen.call_count, 1) self.assert_('psql' in self.mock_popen.call_args[0][0][0]) communicate = self.mock_popen.return_value.communicate self.assertEquals(communicate.call_args[0][0], b('CREATE EXTENSION foobar;'))
def is_libdir_writable(self): """ Check if the Postgres installation directory is writable. If it is, we will assume that sudo is not required to install/uninstall the library, so the sudo program will not be invoked or its specification will not be required. """ dir = self.call_pg_config('libdir') logger.debug("testing if %s is writable", dir) try: f = tempfile.TemporaryFile(prefix="pgxn-", suffix=".test", dir=dir) f.write(b('test')) f.close() except (IOError, OSError): rv = False else: rv = True return rv
def unpack(self, destdir): zipname = self.filename logger.info(_("unpacking: %s"), zipname) destdir = os.path.abspath(destdir) self.open() try: for fn in self.list_files(): fname = os.path.abspath(os.path.join(destdir, fn)) if not fname.startswith(destdir): raise PgxnClientException(_("archive file '%s' trying to escape!") % fname) # Looks like checking for a trailing / is the only way to # tell if the file is a directory. if fn.endswith("/"): os.makedirs(fname) continue # The directory is not always explicitly present in the archive if not os.path.exists(os.path.dirname(fname)): os.makedirs(os.path.dirname(fname)) # Copy the file content logger.debug(_("saving: %s"), fname) fout = open(fname, "wb") try: data = self.read(fn) # In order to restore the executable bit, I haven't find # anything that looks like an executable flag in the zipinfo, # so look at the hashbangs... isexec = data[:2] == b("#!") fout.write(data) finally: fout.close() if isexec: os.chmod(fname, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) finally: self.close() return self._find_work_directory(destdir)
def test_info_empty(self): output = self._get_output(["info", "--versions", "foobar>=0.43.2"]) self.assertEqual(output, b(""))
def test_info_empty(self): output = self._get_output(['info', '--versions', 'foobar>=0.43.2']) self.assertEqual(output, b(""))
def test_info_op(self): output = self._get_output(['info', '--versions', 'foobar>0.42.0']) self.assertEqual(output, b("""\ foobar 0.43.2b1 testing foobar 0.42.1 stable """))