Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pg_dump support back to PostgresAdmin #351

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 41 additions & 7 deletions lib/gems/pending/util/postgres_admin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,17 @@ def self.restore_pg_basebackup(file)
file
end

def self.backup_pg_dump(opts)
opts = opts.dup
dbname = opts.delete(:dbname)

args = combine_command_args(opts, :format => "c", :file => opts[:local_file], nil => dbname)
args = handle_multi_value_pg_dump_args!(opts, args)

runcmd_with_logging("pg_dump", opts, args)
opts[:local_file]
end

def self.backup_pg_compress(opts)
opts = opts.dup

Expand Down Expand Up @@ -200,13 +211,7 @@ def self.reindex(opts)
end

def self.runcmd(cmd_str, opts, args)
default_args = {:no_password => nil}
default_args[:dbname] = opts[:dbname] if opts[:dbname]
default_args[:username] = opts[:username] if opts[:username]
default_args[:host] = opts[:hostname] if opts[:hostname]
args = default_args.merge(args)

runcmd_with_logging(cmd_str, opts, args)
runcmd_with_logging(cmd_str, opts, combine_command_args(opts, args))
end

def self.runcmd_with_logging(cmd_str, opts, params = {})
Expand All @@ -219,4 +224,33 @@ def self.runcmd_with_logging(cmd_str, opts, params = {})
private_class_method def self.file_type(file)
AwesomeSpawn.run!("file", :params => {:b => nil, nil => file}).output
end

private_class_method def self.combine_command_args(opts, args)
default_args = {:no_password => nil}
default_args[:dbname] = opts[:dbname] if opts[:dbname]
default_args[:username] = opts[:username] if opts[:username]
default_args[:host] = opts[:hostname] if opts[:hostname]
default_args.merge(args)
end

# rubocop:disable Style/SymbolArray
PG_DUMP_MULTI_VALUE_ARGS = [
:t, :table, :T, :"exclude-table", :"exclude-table-data",
:n, :schema, :N, :"exclude-schema"
].freeze
# rubocop:enable Style/SymbolArray
#
# NOTE: Potentially mutates opts hash (args becomes new array and not
# mutated by this method)
private_class_method def self.handle_multi_value_pg_dump_args!(opts, args)
if opts.keys.any? { |key| PG_DUMP_MULTI_VALUE_ARGS.include?(key) }
args = args.to_a
PG_DUMP_MULTI_VALUE_ARGS.each do |table_key|
next unless opts.key?(table_key)
table_val = opts.delete(table_key)
args += Array.wrap(table_val).map! { |v| [table_key, v] }
end
end
args
end
end
155 changes: 155 additions & 0 deletions spec/util/postgres_admin_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,161 @@
require "util/postgres_admin"

describe PostgresAdmin do
describe ".backup_pg_dump" do
subject { described_class }

let(:local_file) { nil }
let(:expected_opts) { {} }
let(:expected_args) { default_args }
let(:default_args) do
{
:no_password => nil,
:format => "c",
:file => local_file,
nil => nil
}
end

before do
expect(subject).to receive(:runcmd_with_logging).with("pg_dump", expected_opts, expected_args)
end

context "with empty args" do
it "runs the command and returns the :local_file opt" do
expect(subject.backup_pg_dump({})).to eq(local_file)
end
end

context "with :local_file in opts" do
let(:local_file) { "/some/path/to/pg.dump" }
let(:expected_opts) { { :local_file => local_file } }

it "runs the command and returns the :local_file opt" do
opts = expected_opts
expect(subject.backup_pg_dump(opts)).to eq(local_file)
end
end

context "with :local_file and :dbname in opts" do
let(:local_file) { "/some/path/to/pg.dump" }
let(:expected_opts) { { :local_file => local_file } }
let(:expected_args) { default_args.merge(nil => "mydb") }

it "runs the command and returns the :local_file opt" do
opts = expected_opts.merge(:dbname => "mydb")
expect(subject.backup_pg_dump(opts)).to eq(local_file)
end
end

context "with :local_file, :dbname, :username, and :password in opts" do
let(:local_file) { "/some/path/to/pg.dump" }
let(:expected_opts) do
{
:local_file => local_file,
:username => "admin",
:password => "smartvm"
}
end
let(:expected_args) do
default_args.merge(nil => "mydb", :username => "admin")
end

it "runs the command and returns the :local_file opt" do
opts = expected_opts.merge(:dbname => "mydb")
expect(subject.backup_pg_dump(opts)).to eq(local_file)
end
end

context "with :local_file, :dbname and :hostname in opts" do
let(:local_file) { "/some/path/to/pg.dump" }
let(:expected_opts) { { :local_file => local_file, :hostname => 'foo' } }
let(:expected_args) { default_args.merge(nil => "mydb", :host => 'foo') }

it "runs the command and returns the :local_file opt" do
opts = expected_opts.merge(:dbname => "mydb")
expect(subject.backup_pg_dump(opts)).to eq(local_file)
end
end

shared_examples "for splitting multi value arg" do |arg_type|
arg_as_cmdline_opt = "-#{'-' if arg_type.size > 1}#{arg_type}"

let(:local_file) { "/some/path/to/pg.dump" }

context "with #{arg_as_cmdline_opt} as a single value" do
let(:expected_opts) { { :local_file => local_file } }
let(:expected_args) do
default_args.to_a << [arg_type, "value1"]
end

it "runs the command and returns the :local_file opt" do
opts = expected_opts.merge(arg_type => "value1")
expect(subject.backup_pg_dump(opts)).to eq(local_file)
end
end

context "with #{arg_as_cmdline_opt} as a single value array" do
let(:expected_opts) { { :local_file => local_file } }
let(:expected_args) do
default_args.to_a << [arg_type, "value1"]
end

it "runs the command and returns the :local_file opt" do
opts = expected_opts.merge(arg_type => ["value1"])
expect(subject.backup_pg_dump(opts)).to eq(local_file)
end
end

context "with #{arg_as_cmdline_opt} as a multi value array" do
let(:expected_opts) { { :local_file => local_file } }
let(:expected_args) do
default_args.to_a << [arg_type, "value1"] << [arg_type, "value2"]
end

it "runs the command and returns the :local_file opt" do
opts = expected_opts.merge(arg_type => %w[value1 value2])
expect(subject.backup_pg_dump(opts)).to eq(local_file)
end
end
end

context "with :local_file, :t in opts" do
include_examples "for splitting multi value arg", :t
end

context "with :local_file, :table in opts" do
include_examples "for splitting multi value arg", :table
end

context "with :local_file, :T in opts" do
include_examples "for splitting multi value arg", :T
end

context "with :local_file, :exclude-table in opts" do
include_examples "for splitting multi value arg", :"exclude-table"
end

context "with :local_file, :exclude-table-data in opts" do
include_examples "for splitting multi value arg", :"exclude-table-data"
end

context "with :local_file, :t in opts" do
include_examples "for splitting multi value arg", :n
end

context "with :local_file, :table in opts" do
include_examples "for splitting multi value arg", :schema
end

context "with :local_file, :T in opts" do
include_examples "for splitting multi value arg", :N
end

context "with :local_file, :exclude-table in opts" do
include_examples "for splitting multi value arg", :"exclude-schema"
end
end

context "ENV dependent" do
after do
ENV.delete_if { |k, _| k.start_with?("APPLIANCE") }
Expand Down