With the addition of global postgres options, now we don't need the many of the previous postgres options in option.rb. With the addition of validation via option tree, now we dont't need the most of postgres validation code. This PR removes those dead code.
519 lines
19 KiB
Ruby
519 lines
19 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
RSpec.describe Validation do
|
|
describe "#validate_name" do
|
|
it "valid names" do
|
|
[
|
|
"abc",
|
|
"abc123",
|
|
"abc-123",
|
|
"123abc",
|
|
"abc--123",
|
|
"a-b-c-1-2",
|
|
"a" * 63
|
|
].each do |name|
|
|
expect(described_class.validate_name(name)).to be_nil
|
|
end
|
|
end
|
|
|
|
it "invalid names" do
|
|
[
|
|
nil,
|
|
"-abc",
|
|
"abc-",
|
|
"-abc-",
|
|
"ABC",
|
|
"ABC_123",
|
|
"ABC$123",
|
|
"a" * 64
|
|
].each do |name|
|
|
expect { described_class.validate_name(name) }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
|
|
describe "#validate_vm_size" do
|
|
it "valid vm size" do
|
|
expect(described_class.validate_vm_size("standard-2", "x64").name).to eq("standard-2")
|
|
end
|
|
|
|
it "invalid vm size" do
|
|
expect { described_class.validate_vm_size("standard-3", "x64") }.to raise_error described_class::ValidationFailed
|
|
end
|
|
|
|
it "no IO limits for standard x64" do
|
|
io_limits = described_class.validate_vm_size("standard-2", "x64").io_limits
|
|
expect(io_limits.max_ios_per_sec).to be_nil
|
|
expect(io_limits.max_read_mbytes_per_sec).to be_nil
|
|
expect(io_limits.max_write_mbytes_per_sec).to be_nil
|
|
end
|
|
|
|
it "no IO limits for standard arm64" do
|
|
io_limits = described_class.validate_vm_size("standard-2", "arm64").io_limits
|
|
expect(io_limits.max_ios_per_sec).to be_nil
|
|
expect(io_limits.max_read_mbytes_per_sec).to be_nil
|
|
expect(io_limits.max_write_mbytes_per_sec).to be_nil
|
|
end
|
|
|
|
it "no IO limits for standard-gpu" do
|
|
io_limits = described_class.validate_vm_size("standard-gpu-6", "x64").io_limits
|
|
expect(io_limits.max_ios_per_sec).to be_nil
|
|
expect(io_limits.max_read_mbytes_per_sec).to be_nil
|
|
expect(io_limits.max_write_mbytes_per_sec).to be_nil
|
|
end
|
|
end
|
|
|
|
describe "#validate_vm_storage_size" do
|
|
it "valid vm storage sizes" do
|
|
[
|
|
["standard-2", "40"],
|
|
["standard-2", "80"],
|
|
["standard-4", "160"]
|
|
].each do |vm_size, storage_size|
|
|
expect(described_class.validate_vm_storage_size(vm_size, "x64", storage_size)).to eq(storage_size.to_f)
|
|
end
|
|
end
|
|
|
|
it "invalid vm storage sizes" do
|
|
[
|
|
["standard-2", "160"],
|
|
["standard-2", "37.4"],
|
|
["standard-2", ""],
|
|
["standard-2", nil],
|
|
["standard-5", "40"],
|
|
[nil, "40"]
|
|
].each do |vm_size, storage_size|
|
|
expect { described_class.validate_vm_storage_size(vm_size, "x64", storage_size) }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#validate_os_user_name" do
|
|
it "valid os user names" do
|
|
[
|
|
"abc",
|
|
"abc123",
|
|
"abc-123",
|
|
"abc_123",
|
|
"_abc",
|
|
"abc-_-123",
|
|
"a-b-c-1-2",
|
|
"a" * 32
|
|
].each do |name|
|
|
expect(described_class.validate_os_user_name(name)).to be_nil
|
|
end
|
|
end
|
|
|
|
it "invalid os user names" do
|
|
[
|
|
nil,
|
|
"-abc",
|
|
"ABC",
|
|
"123abc",
|
|
"abc$",
|
|
"a" * 33
|
|
].each do |name|
|
|
expect { described_class.validate_os_user_name(name) }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#validate_storage_volumes" do
|
|
it "succeeds if there's at least one volume" do
|
|
expect { described_class.validate_storage_volumes([{encrypted: true}], 0) }.not_to raise_error
|
|
end
|
|
|
|
it "succeeds if rate limits are set" do
|
|
expect { described_class.validate_storage_volumes([{encrypted: true, max_ios_per_sec: 100, max_read_mbytes_per_sec: 10, max_write_mbytes_per_sec: 10}], 0) }.not_to raise_error
|
|
end
|
|
|
|
it "fails if no volumes" do
|
|
expect { described_class.validate_storage_volumes([], 0) }.to raise_error described_class::ValidationFailed
|
|
end
|
|
|
|
it "fails if boot_disk_index out of range" do
|
|
expect { described_class.validate_storage_volumes([{encrypted: true}], -1) }.to raise_error described_class::ValidationFailed
|
|
expect { described_class.validate_storage_volumes([{encrypted: true}], 1) }.to raise_error described_class::ValidationFailed
|
|
end
|
|
|
|
it "fails if contains an invalid key" do
|
|
expect { described_class.validate_storage_volumes([xyz: 1], 0) }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
|
|
describe "#validate_minio_username" do
|
|
it "valid minio user names" do
|
|
[
|
|
"abc",
|
|
"abc123",
|
|
"abc-123",
|
|
"abc_123",
|
|
"_abc",
|
|
"abc-_-123",
|
|
"a-b-c-1-2",
|
|
"a" * 32
|
|
].each do |name|
|
|
expect(described_class.validate_minio_username(name)).to be_nil
|
|
end
|
|
end
|
|
|
|
it "invalid minio user names" do
|
|
[
|
|
nil,
|
|
"ab",
|
|
"-abc",
|
|
"ABC",
|
|
"123abc",
|
|
"abc$",
|
|
"a" * 33
|
|
].each do |name|
|
|
expect { described_class.validate_minio_username(name) }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#validate_date" do
|
|
it "valid date" do
|
|
expect(described_class.validate_date("2023-11-30 11:41")).to eq(Time.new(2023, 11, 30, 11, 41, 0, "UTC"))
|
|
expect(described_class.validate_date(Time.new(2023, 11, 30, 11, 41))).to eq(Time.new(2023, 11, 30, 11, 41))
|
|
end
|
|
|
|
it "invalid date" do
|
|
expect { described_class.validate_date("") }.to raise_error described_class::ValidationFailed, "Validation failed for following fields: date"
|
|
expect { described_class.validate_date(nil) }.to raise_error described_class::ValidationFailed, "Validation failed for following fields: date"
|
|
expect { described_class.validate_date("invalid-date", "restore_date") }.to raise_error described_class::ValidationFailed, "Validation failed for following fields: restore_date"
|
|
end
|
|
end
|
|
|
|
describe "#validate_postgres_superuser_password" do
|
|
it "valid password" do
|
|
expect { described_class.validate_postgres_superuser_password("Dummy-pass-123", "Dummy-pass-123") }.not_to raise_error
|
|
end
|
|
|
|
it "invalid password" do
|
|
expect { described_class.validate_postgres_superuser_password("", "") }.to raise_error(described_class::ValidationFailed)
|
|
expect { described_class.validate_postgres_superuser_password("Short1", "Short1") }.to raise_error(described_class::ValidationFailed)
|
|
expect { described_class.validate_postgres_superuser_password("NOLOWERCASE123", "NOLOWERCASE123") }.to raise_error(described_class::ValidationFailed)
|
|
expect { described_class.validate_postgres_superuser_password("nouppercase123", "nouppercase123") }.to raise_error(described_class::ValidationFailed)
|
|
expect { described_class.validate_postgres_superuser_password("nodigitNODIGIT", "nodigitNODIGIT") }.to raise_error(described_class::ValidationFailed)
|
|
expect { described_class.validate_postgres_superuser_password("Different12345", "dIFFERENT12345") }.to raise_error(described_class::ValidationFailed)
|
|
end
|
|
end
|
|
|
|
describe "#validate_port_range" do
|
|
it "valid port range" do
|
|
expect(described_class.validate_port_range("1234")).to eq([1234])
|
|
expect(described_class.validate_port_range("1234..1235")).to eq([1234, 1235])
|
|
expect(described_class.validate_port_range("1234..1234")).to eq([1234, 1234])
|
|
end
|
|
|
|
it "invalid port range" do
|
|
expect { described_class.validate_port_range("") }.to raise_error described_class::ValidationFailed
|
|
expect { described_class.validate_port_range("65555") }.to raise_error described_class::ValidationFailed
|
|
expect { described_class.validate_port_range("0..65555") }.to raise_error described_class::ValidationFailed
|
|
expect { described_class.validate_port_range("10..9") }.to raise_error described_class::ValidationFailed
|
|
expect { described_class.validate_port_range("65556..65556") }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
|
|
describe "#validate_port" do
|
|
it "valid port" do
|
|
expect(described_class.validate_port(:src_port, "1234")).to eq(1234)
|
|
end
|
|
|
|
it "invalid port" do
|
|
expect { described_class.validate_port(:src_port, "abc") }.to raise_error described_class::ValidationFailed
|
|
expect { described_class.validate_port(:dst_port, "65555") }.to raise_error described_class::ValidationFailed
|
|
expect { described_class.validate_port(:dst_port, "-1") }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
|
|
describe "#validate_load_balancer_ports" do
|
|
it "validates list of ports" do
|
|
expect { described_class.validate_load_balancer_ports([[80, 80]]) }.not_to raise_error
|
|
end
|
|
|
|
it "validates list of ports which hold duplicates" do
|
|
expect { described_class.validate_load_balancer_ports([[80, 80], [443, 80]]) }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
|
|
describe "#validate_cidr" do
|
|
it "valid cidr" do
|
|
expect { described_class.validate_cidr("0.0.0.0/0") }.not_to raise_error
|
|
expect { described_class.validate_cidr("0.0.0.0/1") }.not_to raise_error
|
|
expect { described_class.validate_cidr("192.168.1.0/24") }.not_to raise_error
|
|
expect { described_class.validate_cidr("255.255.255.255/0") }.not_to raise_error
|
|
|
|
expect { described_class.validate_cidr("::/0") }.not_to raise_error
|
|
expect { described_class.validate_cidr("::1/128") }.not_to raise_error
|
|
expect { described_class.validate_cidr("2001:db8::/32") }.not_to raise_error
|
|
end
|
|
|
|
it "invalid cidr" do
|
|
expect { described_class.validate_cidr("192.168.1.256/24") }.to raise_error described_class::ValidationFailed
|
|
expect { described_class.validate_cidr("10.256.0.0/8") }.to raise_error described_class::ValidationFailed
|
|
expect { described_class.validate_cidr("172.16.0.0/33") }.to raise_error described_class::ValidationFailed
|
|
expect { described_class.validate_cidr("not_a_cidr") }.to raise_error described_class::ValidationFailed
|
|
|
|
expect { described_class.validate_cidr("::1/129") }.to raise_error described_class::ValidationFailed
|
|
expect { described_class.validate_cidr("::1/::1") }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
|
|
describe "#validate_boot_image" do
|
|
it "valid boot image" do
|
|
expect { described_class.validate_boot_image("ubuntu-jammy") }.not_to raise_error
|
|
expect { described_class.validate_boot_image("almalinux-9") }.not_to raise_error
|
|
end
|
|
|
|
it "invalid boot image" do
|
|
expect { described_class.validate_boot_image("invalid-boot-image") }.to raise_error described_class::ValidationFailed
|
|
expect { described_class.validate_boot_image("postgres-ubuntu-2204") }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
|
|
describe "#validate_short_text" do
|
|
it "valid short text" do
|
|
expect { described_class.validate_short_text("abcABC123()!?* ", "name") }.not_to raise_error
|
|
end
|
|
|
|
it "invalid short text" do
|
|
expect { described_class.validate_short_text("", "name") }.to raise_error described_class::ValidationFailed
|
|
expect { described_class.validate_short_text("a" * 256, "name") }.to raise_error described_class::ValidationFailed
|
|
expect { described_class.validate_short_text("'", "name") }.to raise_error described_class::ValidationFailed
|
|
expect { described_class.validate_short_text("%", "name") }.to raise_error described_class::ValidationFailed
|
|
expect { described_class.validate_short_text("~", "name") }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
|
|
describe "#validate_cloudflare_turnstile" do
|
|
it "no ops when cloudflare site key not configured" do
|
|
expect(Config).to receive(:cloudflare_turnstile_site_key).and_return(nil)
|
|
expect(described_class.validate_cloudflare_turnstile("cf_response")).to be_nil
|
|
end
|
|
|
|
it "valid cloudflare response" do
|
|
expect(Config).to receive(:cloudflare_turnstile_site_key).and_return("cf_site_key")
|
|
Excon.stub({url: "https://challenges.cloudflare.com/turnstile/v0/siteverify", method: :post}, {status: 200, body: {"success" => true}.to_json})
|
|
expect(described_class.validate_cloudflare_turnstile("cf_response")).to be_nil
|
|
end
|
|
|
|
it "invalid cloudflare response" do
|
|
expect(Config).to receive(:cloudflare_turnstile_site_key).and_return("cf_site_key")
|
|
Excon.stub({url: "https://challenges.cloudflare.com/turnstile/v0/siteverify", method: :post}, {status: 200, body: {"success" => false, "error-codes" => "123"}.to_json})
|
|
expect { described_class.validate_cloudflare_turnstile("cf_response") }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#validate_account_name" do
|
|
it "valid account names" do
|
|
[
|
|
"John Doe",
|
|
"john doe",
|
|
"John Doe-Smith",
|
|
"Jøhn Döe",
|
|
"John2 Doe",
|
|
"J" * 63
|
|
].each do |name|
|
|
expect(described_class.validate_account_name(name)).to be_nil
|
|
end
|
|
end
|
|
|
|
it "invalid account names" do
|
|
[
|
|
nil,
|
|
"",
|
|
" John Doe",
|
|
"1john Doe",
|
|
".john Doe",
|
|
"https://example.com",
|
|
"Click this link: http://example.com",
|
|
"Click this link example.com",
|
|
"🚀 emojis not allowed",
|
|
"J" * 64
|
|
].each do |name|
|
|
expect { described_class.validate_account_name(name) }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#validate_url" do
|
|
it "valid account names" do
|
|
[
|
|
"https://example.com",
|
|
"https://example.com:1234"
|
|
].each do |url|
|
|
expect(described_class.validate_url(url)).to be_nil
|
|
end
|
|
end
|
|
|
|
it "invalid account names" do
|
|
[
|
|
nil,
|
|
"",
|
|
"1.2.3.4",
|
|
"http://example.com",
|
|
"https://",
|
|
"ftp://example.com"
|
|
].each do |url|
|
|
expect { described_class.validate_url(url) }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#validate_vcpu_quota" do
|
|
it "sufficient cpu quota" do
|
|
p = instance_double(Project, current_resource_usage: 5, effective_quota_value: 10, quota_available?: true)
|
|
expect { described_class.validate_vcpu_quota(p, "VmVCpu", 2) }.not_to raise_error
|
|
end
|
|
|
|
it "insufficient cpu quota" do
|
|
p = instance_double(Project, current_resource_usage: 10, effective_quota_value: 10, quota_available?: false)
|
|
expect { described_class.validate_vcpu_quota(p, "VmVCpu", 2) }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
|
|
describe "#validate_billing_rate" do
|
|
it "valid billing rate" do
|
|
expect { described_class.validate_billing_rate("VmVCpu", "standard", "hetzner-fsn1") }.not_to raise_error
|
|
end
|
|
|
|
it "invalid billing rate" do
|
|
expect { described_class.validate_billing_rate("VmVCpu", "burstable", "latitude-fra") }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
|
|
describe "#validate_load_balancer_stack" do
|
|
it "valid load balancer stack" do
|
|
expect { described_class.validate_load_balancer_stack("ipv4") }.not_to raise_error
|
|
expect { described_class.validate_load_balancer_stack("ipv6") }.not_to raise_error
|
|
expect { described_class.validate_load_balancer_stack("dual") }.not_to raise_error
|
|
end
|
|
|
|
it "invalid load balancer stack" do
|
|
expect { described_class.validate_load_balancer_stack("invalid") }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
|
|
describe "#validate_kubernetes_name" do
|
|
it "valid names" do
|
|
[
|
|
"abc",
|
|
"abc123",
|
|
"abc-123",
|
|
"123abc",
|
|
"abc--123",
|
|
"a-b-c-1-2",
|
|
"a" * 40
|
|
].each do |name|
|
|
expect(described_class.validate_kubernetes_name(name)).to be_nil
|
|
end
|
|
end
|
|
|
|
it "invalid names" do
|
|
[
|
|
nil,
|
|
"-abc",
|
|
"abc-",
|
|
"-abc-",
|
|
"ABC",
|
|
"ABC_123",
|
|
"ABC$123",
|
|
"a" * 42
|
|
].each do |name|
|
|
expect { described_class.validate_kubernetes_name(name) }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#validate_kubernetes_cp_node_count" do
|
|
it "valid numbers" do
|
|
[1, 3].each do |count|
|
|
expect(described_class.validate_kubernetes_cp_node_count(count)).to be_nil
|
|
end
|
|
end
|
|
|
|
it "invalid numbers" do
|
|
[-37, 0, 2, 4, 5].each do |count|
|
|
expect { described_class.validate_kubernetes_cp_node_count(count) }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#validate_private_location_name" do
|
|
it "validates aws region names" do
|
|
expect { described_class.validate_provider_location_name("aws", "us-east-1") }.not_to raise_error
|
|
expect { described_class.validate_provider_location_name("aws", "us-west-2") }.to raise_error described_class::ValidationFailed
|
|
expect { described_class.validate_provider_location_name("azure", "us-east-1") }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
|
|
describe "#validate_victoria_metrics_username" do
|
|
it "valid usernames" do
|
|
[
|
|
"abc",
|
|
"abc123",
|
|
"abc-123",
|
|
"abc_123",
|
|
"abc--123",
|
|
"a-b-c-1-2",
|
|
"a_b_c_1_2",
|
|
"a" * 32
|
|
].each do |username|
|
|
expect(described_class.validate_victoria_metrics_username(username)).to be_nil
|
|
end
|
|
end
|
|
|
|
it "invalid usernames" do
|
|
[
|
|
nil,
|
|
"ab",
|
|
"-abc",
|
|
"ABC",
|
|
"123abc",
|
|
"abc$",
|
|
"a" * 33
|
|
].each do |username|
|
|
expect { described_class.validate_victoria_metrics_username(username) }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#validate_victoria_metrics_storage_size" do
|
|
it "valid storage sizes" do
|
|
[1, 100, 2000, 4000].each do |size|
|
|
expect(described_class.validate_victoria_metrics_storage_size(size)).to eq(size)
|
|
end
|
|
end
|
|
|
|
it "invalid storage sizes" do
|
|
[0, -1, 4001, 5000].each do |size|
|
|
expect { described_class.validate_victoria_metrics_storage_size(size) }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
|
|
it "converts string input to integer" do
|
|
expect(described_class.validate_victoria_metrics_storage_size("100")).to eq(100)
|
|
end
|
|
end
|
|
|
|
describe "#validate_rfc3339_datetime_str" do
|
|
it "validates RFC 3339 datetime strings" do
|
|
["2025-05-12T11:57:24+00:00", "2025-05-12T11:57:24+05:30", "2025-05-12T11:57:24-02:00"].each do |datetime_str|
|
|
expect { described_class.validate_rfc3339_datetime_str(datetime_str) }.not_to raise_error
|
|
end
|
|
end
|
|
|
|
it "invalidates non-RFC 3339 datetime strings" do
|
|
["1747053663", "abc", "2025-05-12T11:57:24"].each do |datetime_str|
|
|
expect { described_class.validate_rfc3339_datetime_str(datetime_str) }.to raise_error described_class::ValidationFailed
|
|
end
|
|
end
|
|
|
|
it "converts string input to Time" do
|
|
expect(described_class.validate_rfc3339_datetime_str("2025-05-12T11:57:24+00:00")).to be_a(Time)
|
|
end
|
|
end
|
|
end
|