Files
ubicloud/spec/model/postgres/postgres_resource_spec.rb
Burak Yucesoy cfe30e27f1 Add port and database name to connection string
This is to be more explicit about the information in the connection string.
With the addition of pgBouncer, we need to specify the port anyway, which
leaves only the database name to be optional. For the sake of consistency,
I decided to include it in the connection string as well.
2025-06-03 05:17:15 +03:00

144 lines
8.3 KiB
Ruby

# frozen_string_literal: true
require_relative "../spec_helper"
RSpec.describe PostgresResource do
subject(:postgres_resource) {
described_class.new(
name: "pg-name",
superuser_password: "dummy-password"
) { it.id = "6181ddb3-0002-8ad0-9aeb-084832c9273b" }
}
it "returns connection string without ubid qualifier" do
expect(Prog::Postgres::PostgresResourceNexus).to receive(:dns_zone).and_return("something").at_least(:once)
expect(postgres_resource).to receive(:hostname_version).and_return("v1")
expect(postgres_resource.connection_string).to eq("postgres://postgres:dummy-password@pg-name.postgres.ubicloud.com:5432/postgres?channel_binding=require")
end
it "returns connection string with ubid qualifier" do
expect(Prog::Postgres::PostgresResourceNexus).to receive(:dns_zone).and_return("something").at_least(:once)
expect(postgres_resource.connection_string).to eq("postgres://postgres:dummy-password@pg-name.pgc60xvcr00a5kbnggj1js4kkq.postgres.ubicloud.com:5432/postgres?channel_binding=require")
end
it "returns connection string with ip address if config is not set" do
expect(postgres_resource).to receive(:representative_server).and_return(instance_double(PostgresServer, vm: instance_double(Vm, ephemeral_net4: "1.2.3.4"))).at_least(:once)
expect(postgres_resource.connection_string).to eq("postgres://postgres:dummy-password@1.2.3.4:5432/postgres?channel_binding=require")
end
it "returns connection string as nil if there is no server" do
expect(postgres_resource).to receive(:representative_server).and_return(nil).at_least(:once)
expect(postgres_resource.connection_string).to be_nil
end
it "returns replication_connection_string" do
s = postgres_resource.replication_connection_string(application_name: "pgubidstandby")
expect(s).to include("ubi_replication@pgc60xvcr00a5kbnggj1js4kkq.postgres.ubicloud.com", "application_name=pgubidstandby", "sslcert=/etc/ssl/certs/server.crt")
end
it "returns has_enough_fresh_servers correctly" do
expect(postgres_resource.servers).to receive(:count).and_return(1, 1)
expect(postgres_resource).to receive(:target_server_count).and_return(1, 2)
expect(postgres_resource.has_enough_fresh_servers?).to be(true)
expect(postgres_resource.has_enough_fresh_servers?).to be(false)
end
it "returns has_enough_ready_servers correctly" do
expect(postgres_resource.servers).to receive(:count).and_return(1, 1)
expect(postgres_resource).to receive(:target_server_count).and_return(1, 2)
expect(postgres_resource.has_enough_ready_servers?).to be(true)
expect(postgres_resource.has_enough_ready_servers?).to be(false)
end
it "returns needs_convergence correctly" do
expect(postgres_resource.servers).to receive(:any?).and_return(true, false, false)
expect(postgres_resource.servers).to receive(:count).and_return(1, 2)
expect(postgres_resource).to receive(:target_server_count).and_return(2, 2)
expect(postgres_resource.needs_convergence?).to be(true)
expect(postgres_resource.needs_convergence?).to be(true)
expect(postgres_resource.needs_convergence?).to be(false)
end
describe "display_state" do
it "returns 'deleting' when strand label is 'destroy'" do
expect(postgres_resource).to receive(:strand).and_return(instance_double(Strand, label: "destroy")).at_least(:once)
expect(postgres_resource.display_state).to eq("deleting")
end
it "returns 'unavailable' when representative server's strand label is 'unavailable'" do
expect(postgres_resource).to receive(:strand).and_return(instance_double(Strand, label: "wait")).at_least(:once)
expect(postgres_resource).to receive(:representative_server).and_return(instance_double(PostgresServer, strand: instance_double(Strand, label: "unavailable")))
expect(postgres_resource.display_state).to eq("unavailable")
end
it "returns 'converging' when the resource has enough ready servers and in maintenance window" do
expect(postgres_resource).to receive(:strand).and_return(instance_double(Strand, label: "wait", children: [instance_double(Strand, prog: "Postgres::ConvergePostgresResource")])).at_least(:once)
expect(postgres_resource).to receive(:has_enough_ready_servers?).and_return(true).at_least(:once)
expect(postgres_resource).to receive(:in_maintenance_window?).and_return(true)
expect(postgres_resource.display_state).to eq("converging")
end
it "returns 'waiting for maintenance window' when the resource has enough ready servers and not in maintenance window" do
expect(postgres_resource).to receive(:strand).and_return(instance_double(Strand, label: "wait", children: [instance_double(Strand, prog: "Postgres::ConvergePostgresResource")])).at_least(:once)
expect(postgres_resource).to receive(:has_enough_ready_servers?).and_return(true).at_least(:once)
expect(postgres_resource).to receive(:in_maintenance_window?).and_return(false).at_least(:once)
expect(postgres_resource.display_state).to eq("waiting for maintenance window")
end
it "returns 'preparing for convergence' when the resource doesn't have enough ready servers" do
expect(postgres_resource).to receive(:strand).and_return(instance_double(Strand, label: "wait", children: [instance_double(Strand, prog: "Postgres::ConvergePostgresResource")])).at_least(:once)
expect(postgres_resource).to receive(:has_enough_ready_servers?).and_return(false).at_least(:once)
expect(postgres_resource.display_state).to eq("preparing for convergence")
end
it "returns 'running' when strand label is 'wait' and has no children" do
expect(postgres_resource).to receive(:strand).and_return(instance_double(Strand, label: "wait", children: [])).at_least(:once)
expect(postgres_resource.display_state).to eq("running")
end
it "returns 'creating' when strand is 'wait_server'" do
expect(postgres_resource).to receive(:strand).and_return(instance_double(Strand, label: "wait_server", children: [])).at_least(:once)
expect(postgres_resource.display_state).to eq("creating")
end
end
it "returns in_maintenance_window? correctly" do
expect(postgres_resource).to receive(:maintenance_window_start_at).and_return(nil)
expect(postgres_resource.in_maintenance_window?).to be(true)
expect(postgres_resource).to receive(:maintenance_window_start_at).and_return(1).at_least(:once)
expect(Time).to receive(:now).and_return(Time.parse("2025-05-01 02:00:00Z"), Time.parse("2025-05-01 04:00:00Z"), Time.parse("2025-05-01 00:00:00Z"))
expect(postgres_resource.in_maintenance_window?).to be(true)
expect(postgres_resource.in_maintenance_window?).to be(false)
expect(postgres_resource.in_maintenance_window?).to be(false)
end
it "returns target_standby_count correctly" do
expect(postgres_resource).to receive(:ha_type).and_return(PostgresResource::HaType::NONE, PostgresResource::HaType::ASYNC, PostgresResource::HaType::SYNC)
(0..2).each { expect(postgres_resource.target_standby_count).to eq(it) }
end
it "returns target_server_count correctly" do
expect(postgres_resource).to receive(:target_standby_count).and_return(0, 1, 2)
(0..2).each { expect(postgres_resource.target_server_count).to eq(it + 1) }
end
it "sets firewall rules" do
firewall = instance_double(Firewall, name: "#{postgres_resource.ubid}-firewall")
expect(postgres_resource).to receive(:private_subnet).exactly(2).and_return(instance_double(PrivateSubnet, firewalls: [firewall], net4: "10.238.50.0/26", net6: "fd19:9c92:e9b9:a1a::/64")).at_least(:once)
expect(postgres_resource).to receive(:firewall_rules).exactly(2).and_return([instance_double(PostgresFirewallRule, cidr: "0.0.0.0/0")])
expect(firewall).to receive(:replace_firewall_rules).with([
{cidr: "0.0.0.0/0", port_range: Sequel.pg_range(5432..5432)},
{cidr: "0.0.0.0/0", port_range: Sequel.pg_range(6432..6432)},
{cidr: "0.0.0.0/0", port_range: Sequel.pg_range(22..22)},
{cidr: "::/0", port_range: Sequel.pg_range(22..22)},
{cidr: "10.238.50.0/26", port_range: Sequel.pg_range(5432..5432)},
{cidr: "10.238.50.0/26", port_range: Sequel.pg_range(6432..6432)},
{cidr: "fd19:9c92:e9b9:a1a::/64", port_range: Sequel.pg_range(5432..5432)},
{cidr: "fd19:9c92:e9b9:a1a::/64", port_range: Sequel.pg_range(6432..6432)}
])
postgres_resource.set_firewall_rules
end
end