Ejemplo n.º 1
0
 def test_min_version_failure_raises(self):
     min_ver = (constants.MIN_VER[0], constants.MIN_VER[1] + 10,
                constants.MIN_VER[2])
     LOGGER.debug('Setting pgdumplib.constants.MIN_VER to %s', min_ver)
     with mock.patch('pgdumplib.constants.MIN_VER', min_ver):
         with self.assertRaises(ValueError):
             pgdumplib.load('build/data/dump.not-compressed')
Ejemplo n.º 2
0
    def test_invalid_dump_file(self):
        with tempfile.NamedTemporaryFile('wb') as temp:
            temp.write(b'PGBAD')
            with open('build/data/dump.not-compressed', 'rb') as handle:
                handle.read(5)
                temp.write(handle.read())

            with self.assertRaises(ValueError):
                pgdumplib.load(temp.name)
Ejemplo n.º 3
0
 def test_invalid_block_type_in_data(self):
     dmp = pgdumplib.new('test')
     dmp.add_entry(constants.TABLE_DATA, '', 'block_table', dump_id=128)
     with gzip.open(pathlib.Path(dmp._temp_dir.name) / '128.gz', 'wb') as h:
         h.write(b'1\t\1\t\1\n')
     with mock.patch('pgdumplib.constants.BLK_DATA', b'\x02'):
         dmp.save('build/data/dump.test')
     with self.assertRaises(RuntimeError):
         pgdumplib.load('build/data/dump.test')
Ejemplo n.º 4
0
    def test_runtime_error_when_pos_not_set(self):
        dmp = pgdumplib.new('test')
        dmp.add_entry(constants.TABLE_DATA, 'public', 'table', dump_id=32)
        with gzip.open(pathlib.Path(dmp._temp_dir.name) / '32.gz', 'wb') as h:
            h.write(b'1\t\1\t\1\n')

        with mock.patch('pgdumplib.constants.K_OFFSET_POS_SET', 9):
            dmp.save('build/data/dump.test')

        with self.assertRaises(RuntimeError):
            pgdumplib.load('build/data/dump.test')
Ejemplo n.º 5
0
    def test_dump_id_mismatch_in_data(self):
        dmp = pgdumplib.new('test')
        dmp.add_entry(constants.TABLE_DATA, '', 'block_table', dump_id=1024)
        with gzip.open(pathlib.Path(dmp._temp_dir.name) / '1024.gz',
                       'wb') as handle:
            handle.write(b'1\t\1\t\1\n')
        dmp.save('build/data/dump.test')

        with mock.patch('pgdumplib.dump.Dump._read_block_header') as rbh:
            rbh.return_value = constants.BLK_DATA, 2048
            with self.assertRaises(RuntimeError):
                pgdumplib.load('build/data/dump.test')
Ejemplo n.º 6
0
 def test_encoding_no_entries(self):
     dmp = pgdumplib.new('test', 'LATIN1')
     dmp.entries = []
     self.assertEqual(dmp.encoding, 'LATIN1')
     dmp.save('build/data/dump.test')
     dmp = pgdumplib.load('build/data/dump.test')
     self.assertEqual(dmp.encoding, 'UTF8')
Ejemplo n.º 7
0
    def test_bad_encoding(self):
        dmp = pgdumplib.new('test')
        dmp.entries[0].defn = 'BAD ENTRY WILL FAIL'
        dmp.save('build/data/dump.test')

        dmp = pgdumplib.load('build/data/dump.test')
        self.assertEqual(dmp.encoding, 'UTF8')
Ejemplo n.º 8
0
    def test_encoding_not_first_entry(self):
        dmp = pgdumplib.new('test', 'LATIN1')
        entries = dmp.entries
        dmp.entries = [entries[1], entries[2], entries[0]]
        self.assertEqual(dmp.encoding, 'LATIN1')
        dmp.save('build/data/dump.test')

        dmp = pgdumplib.load('build/data/dump.test')
        self.assertEqual(dmp.encoding, 'LATIN1')
Ejemplo n.º 9
0
 def test_no_data(self):
     dmp = pgdumplib.new('test')
     dmp.add_entry(constants.TABLE_DATA, '', 'empty_table', dump_id=5)
     with gzip.open(pathlib.Path(dmp._temp_dir.name) / '5.gz', 'wb') as h:
         h.write(b'')
     dmp.save('build/data/dump.test')
     dmp = pgdumplib.load('build/data/dump.test')
     data = [line for line in dmp.table_data('', 'empty_table')]
     self.assertEqual(len(data), 0)
Ejemplo n.º 10
0
    def test_read_blobs(self):
        conn = psycopg2.connect(os.environ['POSTGRES_URI'])
        cursor = conn.cursor()
        cursor.execute(BLOB_COUNT_SQL)
        expectation = cursor.fetchone()[0]
        conn.close()

        dmp = pgdumplib.load(self.dump_path, self.CONVERTER)
        blobs = []
        for oid, blob in dmp.blobs():
            self.assertIsInstance(oid, int)
            self.assertIsInstance(blob, bytes)
            blobs.append((oid, blob))
        self.assertEqual(len(blobs), expectation)
Ejemplo n.º 11
0
def main():
    args = parse_cli_arguments()
    dump = pgdumplib.load(args.file[0])
    if args.format == 'json':
        out = sys.stdout if args.out == '-' else open(args.out, 'wt')
        as_json(args, dump, out)
    elif args.format == 'html':
        if args.out == '-':
            sys.stderr.write('Must specify a directory for HTML output\n')
            sys.exit(1)
        out_dir = pathlib.Path(args.out)
        if out_dir.exists() and not out_dir.is_dir():
            sys.stderr.write('Must specify a directory for HTML output\n')
            sys.exit(1)
        elif not out_dir.exists():
            out_dir.mkdir()
        buffer = io.StringIO()
        as_json(args, dump, buffer, 0)
        buffer.seek(0)
        html.as_html(buffer.read(), out_dir)
Ejemplo n.º 12
0
    def run(self) -> typing.NoReturn:
        """Implement as core logic for generating the project"""
        if self.project_path.exists() and not self.args.force:
            common.exit_application(
                '{} already exists'.format(self.project_path), 3)

        LOGGER.info('Generating project in %s', self.project_path)
        LOGGER.debug('args: %r', self.args)

        if self.args.ignore:
            with open(self.args.ignore, 'r') as handle:
                for line in handle:
                    self.ignore.add(line.strip())
            LOGGER.info('Ignoring %i files', len(self.ignore))

        if self.args.extract:
            LOGGER.info('Dumping schema from postgresql://%s:%s/%s',
                        self.args.host, self.args.port, self.args.dbname)
            pgdump.dump(self.args, self.dump_path)

        LOGGER.debug('Loading dump from %s', self.dump_path)
        self.dump = pgdumplib.load(self.dump_path)
        self.structure = Structure(self.dump.entries)

        self._create_directories()
        self._create_project_file()

        if self.args.extract_roles:
            self._extract_roles()
            self._process_acls()
            self._create_role_files()
            self._create_group_files()
            self._create_user_files()

        self._create_namespace_files(constants.CAST)
        self._create_namespace_files(constants.COLLATION)
        self._create_namespace_files(constants.CONVERSION)
        self._create_files(constants.DOMAIN)
        self._create_files(constants.EVENT_TRIGGER)
        self._create_files(constants.FOREIGN_DATA_WRAPPER)
        self._create_files(constants.FUNCTION)
        self._create_namespace_files(constants.MATERIALIZED_VIEW)
        self._create_operator_files()
        self._create_namespace_files(constants.PROCEDURE)
        self._create_namespace_files(constants.PUBLICATION)
        self._create_schema_files()
        self._create_files(constants.SEQUENCE)
        self._create_namespace_files(constants.SUBSCRIPTION)
        self._create_files(constants.SERVER)
        self._create_files(constants.TABLE)
        self._create_namespace_files(constants.TABLESPACE)
        self._create_namespace_files(constants.TYPE)
        self._create_namespace_files(constants.TEXT_SEARCH_CONFIGURATION)
        self._create_namespace_files(constants.TEXT_SEARCH_DICTIONARY)
        self._create_files(constants.USER_MAPPING)
        self._create_files(constants.VIEW)

        remaining = collections.Counter()
        for entry in [
                e for e in self.dump.entries if e.dump_id not in self.processed
                and e.desc != constants.SEARCHPATH
        ]:
            remaining['{}:{}'.format(entry.section, entry.desc)] += 1

        for key in sorted(remaining.keys(), reverse=True):
            LOGGER.info('Remaining %s: %i', key, remaining[key])

        if self.args.save_remaining:
            LOGGER.debug('Writing remaining.yaml')
            with open(self.project_path / 'remaining.yaml', 'w') as handle:
                storage.yaml_dump(handle, [
                    dataclasses.asdict(e) for e in self.dump.entries
                    if e.dump_id not in self.processed
                ])

        if self.args.gitkeep:
            storage.remove_unneeded_gitkeeps(self.project_path)
        if self.args.remove_empty_dirs:
            storage.remove_empty_directories(self.project_path)
Ejemplo n.º 13
0
 def setUpClass(cls) -> None:
     cls.dump = pgdumplib.load(
         pathlib.Path('build') / 'data' / cls.PATH, cls.CONVERTER)
Ejemplo n.º 14
0
 def _read_dump(self):
     return pgdumplib.load(self.local_path)
Ejemplo n.º 15
0
 def setUp(self):
     dmp = pgdumplib.load('build/data/dump.compressed')
     dmp.save('build/data/dump.test')
     self.original = pgdumplib.load('build/data/dump.compressed')
     self.saved = pgdumplib.load('build/data/dump.test')
Ejemplo n.º 16
0
    def test_dump_expectations(self):
        dmp = pgdumplib.new('test', 'UTF8')
        database = dmp.add_entry(
            desc=constants.DATABASE,
            tag='postgres',
            owner='postgres',
            defn="""\
            CREATE DATABASE postgres
              WITH TEMPLATE = template0
                   ENCODING = 'UTF8'
                   LC_COLLATE = 'en_US.utf8'
                   LC_CTYPE = 'en_US.utf8';""",
            drop_stmt='DROP DATABASE postgres')

        dmp.add_entry(
            constants.COMMENT,
            tag='DATABASE postgres',
            owner='postgres',
            defn="""\
            COMMENT ON DATABASE postgres
                 IS 'default administrative connection database';""",
            dependencies=[database.dump_id])

        example = dmp.add_entry(
            constants.TABLE, 'public', 'example', 'postgres',
            'CREATE TABLE public.example (\
              id UUID NOT NULL PRIMARY KEY, \
              created_at TIMESTAMP WITH TIME ZONE, \
              value TEXT NOT NULL);',
            'DROP TABLE public.example')

        columns = 'id', 'created_at', 'value'

        fake = faker.Faker()
        fake.add_provider(date_time)

        rows = [
            (uuid.uuid4(), fake.date_time(tzinfo=tz.tzutc()), 'foo'),
            (uuid.uuid4(), fake.date_time(tzinfo=tz.tzutc()), 'bar'),
            (uuid.uuid4(), fake.date_time(tzinfo=tz.tzutc()), 'baz'),
            (uuid.uuid4(), fake.date_time(tzinfo=tz.tzutc()), 'qux')
        ]

        with dmp.table_data_writer(example, columns) as writer:
            for row in rows:
                writer.append(*row)

        row = (uuid.uuid4(), fake.date_time(tzinfo=tz.tzutc()), None)
        rows.append(row)

        # Append a second time to get same writer
        with dmp.table_data_writer(example, columns) as writer:
            writer.append(*row)

        dmp.save('build/data/dump.test')

        test_file = pathlib.Path('build/data/dump.test')
        self.assertTrue(test_file.exists())

        dmp = pgdumplib.load(test_file, converters.SmartDataConverter)
        entry = dmp.get_entry(database.dump_id)
        self.assertEqual(entry.desc, 'DATABASE')
        self.assertEqual(entry.owner, 'postgres')
        self.assertEqual(entry.tag, 'postgres')
        values = [row for row in dmp.table_data('public', 'example')]
        self.assertListEqual(values, rows)
Ejemplo n.º 17
0
 def test_missing_file_raises_value_error(self):
     path = pathlib.Path(tempfile.gettempdir()) / str(uuid.uuid4())
     with self.assertRaises(ValueError):
         pgdumplib.load(path)