From 0d53a27447eac1f1184812d29877081a8b88f1f7 Mon Sep 17 00:00:00 2001 From: Joey Stack Date: Fri, 6 Mar 2026 08:14:04 -0700 Subject: [PATCH 1/5] Limit what we iteraate over in providers --- lib/puppet/provider/mysql_database/mysql.rb | 27 +++++++++++++++------ lib/puppet/provider/mysql_grant/mysql.rb | 9 ++++--- lib/puppet/provider/mysql_user/mysql.rb | 11 ++++++--- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/lib/puppet/provider/mysql_database/mysql.rb b/lib/puppet/provider/mysql_database/mysql.rb index 2b2f1a925..8078614aa 100644 --- a/lib/puppet/provider/mysql_database/mysql.rb +++ b/lib/puppet/provider/mysql_database/mysql.rb @@ -6,24 +6,35 @@ commands mysql_raw: 'mysql' - def self.instances - mysql_caller('show databases', 'regular').split("\n").map do |name| + def self.instances(managed_databases = nil) + db_list = if managed_databases && !managed_databases.empty? + managed_databases + else + mysql_caller('show databases', 'regular').split("\n") + end + db_list.map do |name| attributes = {} - mysql_caller(["show variables like '%_database'", name], 'regular').split("\n").each do |line| - k, v = line.split(%r{\s}) - attributes[k] = v + begin + mysql_caller(["show variables like '%_database'", name], 'regular').split("\n").each do |line| + k, v = line.split(%r{\s}) + attributes[k] = v + end + rescue Puppet::ExecutionFailure => e + raise unless e.message.include?('Unknown database') + + next end - new(name:, + new(name: name, ensure: :present, charset: attributes['character_set_database'], collate: attributes['collation_database']) - end + end.compact end # We iterate over each mysql_database entry in the catalog and compare it against # the contents of the property_hash generated by self.instances def self.prefetch(resources) - databases = instances + databases = instances(resources.keys) resources.each_key do |database| provider = databases.find { |db| db.name == database } resources[database].provider = provider if provider diff --git a/lib/puppet/provider/mysql_grant/mysql.rb b/lib/puppet/provider/mysql_grant/mysql.rb index 9413f0a09..0575a6cb4 100644 --- a/lib/puppet/provider/mysql_grant/mysql.rb +++ b/lib/puppet/provider/mysql_grant/mysql.rb @@ -6,9 +6,10 @@ commands mysql_raw: 'mysql' - def self.instances + def self.instances(managed_users = nil) instance_configs = {} - users.map do |user| + user_list = managed_users && !managed_users.empty? ? managed_users : users + user_list.map do |user| user_string = cmd_user(user) query = "SHOW GRANTS FOR #{user_string};" begin @@ -120,7 +121,9 @@ def self.instances end def self.prefetch(resources) - users = instances + # Extract unique user@host values from grant resource names (format: user@host/table) + managed_users = resources.keys.map { |name| name.rpartition('/').first }.uniq + users = instances(managed_users) resources.each_key do |name| if provider = users.find { |user| user.name == name } # rubocop:disable Lint/AssignmentInCondition resources[name].provider = provider diff --git a/lib/puppet/provider/mysql_user/mysql.rb b/lib/puppet/provider/mysql_user/mysql.rb index 7ab636bd8..67edfaecc 100644 --- a/lib/puppet/provider/mysql_user/mysql.rb +++ b/lib/puppet/provider/mysql_user/mysql.rb @@ -7,8 +7,13 @@ # Build a property_hash containing all the discovered information about MySQL # users. - def self.instances - users = mysql_caller("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user where HOST IS NOT NULL AND HOST != ''", 'regular').split("\n") + def self.instances(managed_users = nil) + if managed_users && !managed_users.empty? + user_list = managed_users.map { |u| "'" + u.gsub("'", "''") + "'" }.join(', ') + users = mysql_caller("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user WHERE HOST IS NOT NULL AND HOST != '' AND CONCAT(User, '@', Host) IN (#{user_list})", 'regular').split("\n") + else + users = mysql_caller("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user where HOST IS NOT NULL AND HOST != ''", 'regular').split("\n") + end # users = users_full.reject { |user| user == 'PUBLIC@' } # To reduce the number of calls to MySQL we collect all the properties in # one big swoop. @@ -49,7 +54,7 @@ def self.instances # We iterate over each mysql_user entry in the catalog and compare it against # the contents of the property_hash generated by self.instances def self.prefetch(resources) - users = instances + users = instances(resources.keys) # rubocop:disable Lint/AssignmentInCondition resources.each_key do |name| if provider = users.find { |user| user.name == name } From 837baac3aefcde2a9bb3e2ffa707d9fa695b0da9 Mon Sep 17 00:00:00 2001 From: Joey Stack Date: Fri, 6 Mar 2026 08:22:44 -0700 Subject: [PATCH 2/5] indent the end --- lib/puppet/provider/mysql_database/mysql.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/puppet/provider/mysql_database/mysql.rb b/lib/puppet/provider/mysql_database/mysql.rb index 8078614aa..af8112d62 100644 --- a/lib/puppet/provider/mysql_database/mysql.rb +++ b/lib/puppet/provider/mysql_database/mysql.rb @@ -18,7 +18,7 @@ def self.instances(managed_databases = nil) mysql_caller(["show variables like '%_database'", name], 'regular').split("\n").each do |line| k, v = line.split(%r{\s}) attributes[k] = v - end + end rescue Puppet::ExecutionFailure => e raise unless e.message.include?('Unknown database') From eed8e5224cdb880e4df34ac41d42eb7fa003ae88 Mon Sep 17 00:00:00 2001 From: Joey Stack Date: Mon, 27 Jul 2026 08:17:27 -0700 Subject: [PATCH 3/5] Add testing specific to changes --- .../provider/mysql_database/mysql_spec.rb | 21 ++++++++++++ .../puppet/provider/mysql_grant/mysql_spec.rb | 34 +++++++++++++++++++ .../puppet/provider/mysql_user/mysql_spec.rb | 26 ++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 spec/unit/puppet/provider/mysql_grant/mysql_spec.rb diff --git a/spec/unit/puppet/provider/mysql_database/mysql_spec.rb b/spec/unit/puppet/provider/mysql_database/mysql_spec.rb index fd4c07e7a..bb942da50 100644 --- a/spec/unit/puppet/provider/mysql_database/mysql_spec.rb +++ b/spec/unit/puppet/provider/mysql_database/mysql_spec.rb @@ -41,6 +41,14 @@ databases = provider.class.instances.map(&:name) expect(parsed_databases).to match_array(databases) end + + it 'skips managed databases that no longer exist' do + allow(provider.class).to receive(:mysql_caller).with(["show variables like '%_database'", 'managed_existing'], 'regular').and_return("character_set_database latin1\ncollation_database latin1_swedish_ci\nskip_show_database OFF") # rubocop:disable Layout/LineLength + allow(provider.class).to receive(:mysql_caller).with(["show variables like '%_database'", 'managed_missing'], 'regular').and_raise(Puppet::ExecutionFailure, 'ERROR 1049 (42000): Unknown database') + + databases = provider.class.instances(['managed_existing', 'managed_missing']).map(&:name) + expect(databases).to eq(['managed_existing']) + end end describe 'self.prefetch' do @@ -48,6 +56,19 @@ provider.class.instances provider.class.prefetch({}) end + + it 'only prefetches managed databases from resources' do + resources = { + 'db_one' => instance_double(Puppet::Type.type(:mysql_database)), + 'db_two' => instance_double(Puppet::Type.type(:mysql_database)) + } + + allow(provider.class).to receive(:instances).with(['db_one', 'db_two']).and_return([]) + resources.values.each { |res| allow(res).to receive(:provider=) } + + provider.class.prefetch(resources) + expect(provider.class).to have_received(:instances).with(['db_one', 'db_two']) + end end describe 'create' do diff --git a/spec/unit/puppet/provider/mysql_grant/mysql_spec.rb b/spec/unit/puppet/provider/mysql_grant/mysql_spec.rb new file mode 100644 index 000000000..4a0d151d4 --- /dev/null +++ b/spec/unit/puppet/provider/mysql_grant/mysql_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Puppet::Type.type(:mysql_grant).provider(:mysql) do + describe 'self.prefetch' do + it 'only loads grants for managed users from resources' do + grant_one = instance_double(Puppet::Type.type(:mysql_grant)) + grant_two = instance_double(Puppet::Type.type(:mysql_grant)) + grant_three = instance_double(Puppet::Type.type(:mysql_grant)) + + resources = { + 'alice@localhost/db_one.*' => grant_one, + 'alice@localhost/db_two.*' => grant_two, + 'bob@localhost/db_one.*' => grant_three + } + + alice_provider = instance_double(described_class, name: 'alice@localhost/db_one.*') + bob_provider = instance_double(described_class, name: 'bob@localhost/db_one.*') + + allow(described_class).to receive(:instances).with(['alice@localhost', 'bob@localhost']).and_return([alice_provider, bob_provider]) + allow(grant_one).to receive(:provider=) + allow(grant_two).to receive(:provider=) + allow(grant_three).to receive(:provider=) + + described_class.prefetch(resources) + + expect(described_class).to have_received(:instances).with(['alice@localhost', 'bob@localhost']) + expect(grant_one).to have_received(:provider=).with(alice_provider) + expect(grant_two).not_to have_received(:provider=) + expect(grant_three).to have_received(:provider=).with(bob_provider) + end + end +end diff --git a/spec/unit/puppet/provider/mysql_user/mysql_spec.rb b/spec/unit/puppet/provider/mysql_user/mysql_spec.rb index e5e0e75d5..9227289d8 100644 --- a/spec/unit/puppet/provider/mysql_user/mysql_spec.rb +++ b/spec/unit/puppet/provider/mysql_user/mysql_spec.rb @@ -168,6 +168,19 @@ usernames = provider.class.instances.map(&:name) expect(parsed_users).to match_array(usernames) end + + it 'queries only managed users when user list is provided' do + managed_users = ["joe@localhost", "o'reilly@localhost"] + user_query = "SELECT CONCAT(User, '@',Host) AS User FROM mysql.user WHERE HOST IS NOT NULL AND HOST != '' AND CONCAT(User, '@', Host) IN ('joe@localhost', 'o''reilly@localhost')" + + allow(provider.class).to receive(:mysql_caller).with(user_query, 'regular').and_return("joe@localhost\no'reilly@localhost") + managed_users.each do |user| + allow(provider.class).to receive(:mysql_caller).with("SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'", 'regular').and_return('10 10 10 10 ') # rubocop:disable Layout/LineLength + end + + usernames = provider.class.instances(managed_users).map(&:name) + expect(usernames).to match_array(managed_users) + end end describe 'mysql version and type detection' do @@ -192,6 +205,19 @@ provider.class.instances provider.class.prefetch({}) end + + it 'only prefetches managed users from resources' do + resources = { + 'joe@localhost' => instance_double(Puppet::Type.type(:mysql_user)), + 'jane@localhost' => instance_double(Puppet::Type.type(:mysql_user)) + } + + allow(provider.class).to receive(:instances).with(['joe@localhost', 'jane@localhost']).and_return([]) + resources.values.each { |res| allow(res).to receive(:provider=) } + + provider.class.prefetch(resources) + expect(provider.class).to have_received(:instances).with(['joe@localhost', 'jane@localhost']) + end end describe 'create' do From 0c521c27735d059227fabf7eb77ecb11fe499339 Mon Sep 17 00:00:00 2001 From: Joey Stack Date: Mon, 27 Jul 2026 12:02:43 -0700 Subject: [PATCH 4/5] Update with some edge case testing. --- spec/acceptance/00_mysql_server_spec.rb | 108 ++++++++++++++++++ .../provider/mysql_database/mysql_spec.rb | 14 +++ .../puppet/provider/mysql_grant/mysql_spec.rb | 27 +++++ .../puppet/provider/mysql_user/mysql_spec.rb | 9 ++ 4 files changed, 158 insertions(+) diff --git a/spec/acceptance/00_mysql_server_spec.rb b/spec/acceptance/00_mysql_server_spec.rb index 0d33034a2..282aac429 100644 --- a/spec/acceptance/00_mysql_server_spec.rb +++ b/spec/acceptance/00_mysql_server_spec.rb @@ -83,4 +83,112 @@ class { 'mysql::server': idempotent_apply(pp) end end + + describe 'prefetch with managed subset' do + let(:bootstrap_pp) do + <<-MANIFEST + class { 'mysql::server': + root_password => 'test', + service_enabled => 'true', + service_manage => 'true', + } + MANIFEST + end + + let(:subset_pp) do + <<-MANIFEST + class { 'mysql::server': + root_password => 'test', + service_enabled => 'true', + service_manage => 'true', + } + + mysql_database { 'managed_db': + ensure => 'present', + charset => '#{charset}', + collate => '#{charset}_general_ci', + } + + mysql_user { 'managed_user@localhost': + ensure => 'present', + } + + mysql_grant { 'managed_user@localhost/managed_db.*': + ensure => 'present', + privileges => ['SELECT'], + table => 'managed_db.*', + user => 'managed_user@localhost', + require => [Mysql_user['managed_user@localhost'], Mysql_database['managed_db']], + } + MANIFEST + end + + let(:fixtures_pp) do + <<-MANIFEST + class { 'mysql::server': + root_password => 'test', + service_enabled => 'true', + service_manage => 'true', + } + + mysql_database { 'unmanaged_db': + ensure => 'present', + charset => '#{charset}', + collate => '#{charset}_general_ci', + } + + mysql_user { 'managed_user@localhost': + ensure => 'present', + } + + mysql_user { 'unmanaged_user@localhost': + ensure => 'present', + } + + mysql_grant { 'managed_user@localhost/unmanaged_db.*': + ensure => 'present', + privileges => ['INSERT'], + table => 'unmanaged_db.*', + user => 'managed_user@localhost', + require => [Mysql_user['managed_user@localhost'], Mysql_database['unmanaged_db']], + } + + mysql_grant { 'unmanaged_user@localhost/unmanaged_db.*': + ensure => 'present', + privileges => ['SELECT'], + table => 'unmanaged_db.*', + user => 'unmanaged_user@localhost', + require => [Mysql_user['unmanaged_user@localhost'], Mysql_database['unmanaged_db']], + } + MANIFEST + end + + it 'applies server setup' do + idempotent_apply(bootstrap_pp) + end + + it 'creates managed and unmanaged fixture resources' do + apply_manifest(fixtures_pp, catch_failures: true) + end + + it 'manages only the declared subset idempotently' do + idempotent_apply(subset_pp) + end + + it 'keeps unmanaged resources present' do + probe = run_shell('command -v mysql || command -v mariadb', expect_failures: true) + db_client = probe.stdout.to_s.strip + skip('No mysql/mariadb client available on acceptance target') if db_client.empty? + + db_query = "SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME='unmanaged_db'" + db_result = run_shell("#{db_client} -NBe \"#{db_query}\"") + expect(db_result.exit_code).to eq 0 + expect(db_result.stdout).to match(%r{^unmanaged_db$}) + + user_query = "SELECT CONCAT(user, '@', host) FROM mysql.user WHERE CONCAT(user, '@', host)='unmanaged_user@localhost'" + user_result = run_shell("#{db_client} -NBe \"#{user_query}\"") + expect(user_result.exit_code).to eq 0 + expect(user_result.stdout).to match(%r{^unmanaged_user@localhost$}) + end + end end diff --git a/spec/unit/puppet/provider/mysql_database/mysql_spec.rb b/spec/unit/puppet/provider/mysql_database/mysql_spec.rb index bb942da50..7f391f7ce 100644 --- a/spec/unit/puppet/provider/mysql_database/mysql_spec.rb +++ b/spec/unit/puppet/provider/mysql_database/mysql_spec.rb @@ -49,6 +49,20 @@ databases = provider.class.instances(['managed_existing', 'managed_missing']).map(&:name) expect(databases).to eq(['managed_existing']) end + + it 're-raises unexpected database lookup failures' do + allow(provider.class).to receive(:mysql_caller).with(["show variables like '%_database'", 'managed_broken'], 'regular').and_raise(Puppet::ExecutionFailure, 'ERROR 1044 (42000): Access denied') + + expect { provider.class.instances(['managed_broken']) }.to raise_error(Puppet::ExecutionFailure, 'ERROR 1044 (42000): Access denied') + end + + it 'falls back to full scan when managed database list is empty' do + allow(provider.class).to receive(:mysql_caller).with('show databases', 'regular').and_return("fallback_db\n") + allow(provider.class).to receive(:mysql_caller).with(["show variables like '%_database'", 'fallback_db'], 'regular').and_return("character_set_database latin1\ncollation_database latin1_swedish_ci\nskip_show_database OFF") # rubocop:disable Layout/LineLength + + databases = provider.class.instances([]).map(&:name) + expect(databases).to eq(['fallback_db']) + end end describe 'self.prefetch' do diff --git a/spec/unit/puppet/provider/mysql_grant/mysql_spec.rb b/spec/unit/puppet/provider/mysql_grant/mysql_spec.rb index 4a0d151d4..cccd98703 100644 --- a/spec/unit/puppet/provider/mysql_grant/mysql_spec.rb +++ b/spec/unit/puppet/provider/mysql_grant/mysql_spec.rb @@ -3,6 +3,33 @@ require 'spec_helper' describe Puppet::Type.type(:mysql_grant).provider(:mysql) do + describe 'self.instances' do + it 'loads grants only for the managed users list' do + allow(described_class).to receive(:newer_than).and_return(false) + allow(described_class).to receive(:users).and_return(['unused@localhost']) + allow(described_class).to receive(:mysql_caller).with("SHOW GRANTS FOR 'alice'@'localhost';", 'regular').and_return("GRANT SELECT ON `db_one`.* TO 'alice'@'localhost'\n") + allow(described_class).to receive(:mysql_caller).with("SHOW GRANTS FOR 'bob'@'localhost';", 'regular').and_return("GRANT INSERT ON `db_two`.* TO 'bob'@'localhost'\n") + + instances = described_class.instances(['alice@localhost']) + + expect(described_class).not_to have_received(:users) + expect(described_class).to have_received(:mysql_caller).with("SHOW GRANTS FOR 'alice'@'localhost';", 'regular') + expect(described_class).not_to have_received(:mysql_caller).with("SHOW GRANTS FOR 'bob'@'localhost';", 'regular') + expect(instances.map(&:name)).to eq(['alice@localhost/db_one.*']) + end + + it 'falls back to full user scan when managed user list is empty' do + allow(described_class).to receive(:newer_than).and_return(false) + allow(described_class).to receive(:users).and_return(['alice@localhost']) + allow(described_class).to receive(:mysql_caller).with("SHOW GRANTS FOR 'alice'@'localhost';", 'regular').and_return("GRANT SELECT ON `db_one`.* TO 'alice'@'localhost'\n") + + instances = described_class.instances([]) + + expect(described_class).to have_received(:users) + expect(instances.map(&:name)).to eq(['alice@localhost/db_one.*']) + end + end + describe 'self.prefetch' do it 'only loads grants for managed users from resources' do grant_one = instance_double(Puppet::Type.type(:mysql_grant)) diff --git a/spec/unit/puppet/provider/mysql_user/mysql_spec.rb b/spec/unit/puppet/provider/mysql_user/mysql_spec.rb index 9227289d8..8132991d2 100644 --- a/spec/unit/puppet/provider/mysql_user/mysql_spec.rb +++ b/spec/unit/puppet/provider/mysql_user/mysql_spec.rb @@ -181,6 +181,15 @@ usernames = provider.class.instances(managed_users).map(&:name) expect(usernames).to match_array(managed_users) end + + it 'falls back to full user scan when managed user list is empty' do + full_scan_query = "SELECT CONCAT(User, '@',Host) AS User FROM mysql.user where HOST IS NOT NULL AND HOST != ''" + allow(provider.class).to receive(:mysql_caller).with(full_scan_query, 'regular').and_return('joe@localhost') + allow(provider.class).to receive(:mysql_caller).with("SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = 'joe@localhost'", 'regular').and_return('10 10 10 10 ') # rubocop:disable Layout/LineLength + + usernames = provider.class.instances([]).map(&:name) + expect(usernames).to eq(['joe@localhost']) + end end describe 'mysql version and type detection' do From b5cc7beebf1e448c5dcbe30b8e1b4ba6add4c4a9 Mon Sep 17 00:00:00 2001 From: Joey Stack Date: Thu, 30 Jul 2026 08:20:06 -0700 Subject: [PATCH 5/5] Attempt at remediateing rubocop hiera failures --- lib/puppet/provider/mysql_database/mysql.rb | 14 +++++------ lib/puppet/provider/mysql_grant/mysql.rb | 2 +- .../provider/mysql_database/mysql_spec.rb | 9 ++++--- .../puppet/provider/mysql_grant/mysql_spec.rb | 25 ++++++------------- .../puppet/provider/mysql_user/mysql_spec.rb | 7 +++--- 5 files changed, 24 insertions(+), 33 deletions(-) diff --git a/lib/puppet/provider/mysql_database/mysql.rb b/lib/puppet/provider/mysql_database/mysql.rb index af8112d62..99f111b93 100644 --- a/lib/puppet/provider/mysql_database/mysql.rb +++ b/lib/puppet/provider/mysql_database/mysql.rb @@ -8,11 +8,11 @@ def self.instances(managed_databases = nil) db_list = if managed_databases && !managed_databases.empty? - managed_databases - else - mysql_caller('show databases', 'regular').split("\n") - end - db_list.map do |name| + managed_databases + else + mysql_caller('show databases', 'regular').split("\n") + end + db_list.map { |name| attributes = {} begin mysql_caller(["show variables like '%_database'", name], 'regular').split("\n").each do |line| @@ -24,11 +24,11 @@ def self.instances(managed_databases = nil) next end - new(name: name, + new(name:, ensure: :present, charset: attributes['character_set_database'], collate: attributes['collation_database']) - end.compact + }.compact end # We iterate over each mysql_database entry in the catalog and compare it against diff --git a/lib/puppet/provider/mysql_grant/mysql.rb b/lib/puppet/provider/mysql_grant/mysql.rb index 0575a6cb4..f4097acf6 100644 --- a/lib/puppet/provider/mysql_grant/mysql.rb +++ b/lib/puppet/provider/mysql_grant/mysql.rb @@ -8,7 +8,7 @@ def self.instances(managed_users = nil) instance_configs = {} - user_list = managed_users && !managed_users.empty? ? managed_users : users + user_list = (managed_users && !managed_users.empty?) ? managed_users : users user_list.map do |user| user_string = cmd_user(user) query = "SHOW GRANTS FOR #{user_string};" diff --git a/spec/unit/puppet/provider/mysql_database/mysql_spec.rb b/spec/unit/puppet/provider/mysql_database/mysql_spec.rb index 7f391f7ce..9e0347b96 100644 --- a/spec/unit/puppet/provider/mysql_database/mysql_spec.rb +++ b/spec/unit/puppet/provider/mysql_database/mysql_spec.rb @@ -44,7 +44,9 @@ it 'skips managed databases that no longer exist' do allow(provider.class).to receive(:mysql_caller).with(["show variables like '%_database'", 'managed_existing'], 'regular').and_return("character_set_database latin1\ncollation_database latin1_swedish_ci\nskip_show_database OFF") # rubocop:disable Layout/LineLength - allow(provider.class).to receive(:mysql_caller).with(["show variables like '%_database'", 'managed_missing'], 'regular').and_raise(Puppet::ExecutionFailure, 'ERROR 1049 (42000): Unknown database') + allow(provider.class).to receive(:mysql_caller) + .with(["show variables like '%_database'", 'managed_missing'], 'regular') + .and_raise(Puppet::ExecutionFailure, 'ERROR 1049 (42000): Unknown database') databases = provider.class.instances(['managed_existing', 'managed_missing']).map(&:name) expect(databases).to eq(['managed_existing']) @@ -77,11 +79,10 @@ 'db_two' => instance_double(Puppet::Type.type(:mysql_database)) } - allow(provider.class).to receive(:instances).with(['db_one', 'db_two']).and_return([]) - resources.values.each { |res| allow(res).to receive(:provider=) } + expect(provider.class).to receive(:instances).with(['db_one', 'db_two']).and_return([]) + resources.each_value { |res| allow(res).to receive(:provider=) } provider.class.prefetch(resources) - expect(provider.class).to have_received(:instances).with(['db_one', 'db_two']) end end diff --git a/spec/unit/puppet/provider/mysql_grant/mysql_spec.rb b/spec/unit/puppet/provider/mysql_grant/mysql_spec.rb index cccd98703..570953b08 100644 --- a/spec/unit/puppet/provider/mysql_grant/mysql_spec.rb +++ b/spec/unit/puppet/provider/mysql_grant/mysql_spec.rb @@ -6,26 +6,22 @@ describe 'self.instances' do it 'loads grants only for the managed users list' do allow(described_class).to receive(:newer_than).and_return(false) - allow(described_class).to receive(:users).and_return(['unused@localhost']) - allow(described_class).to receive(:mysql_caller).with("SHOW GRANTS FOR 'alice'@'localhost';", 'regular').and_return("GRANT SELECT ON `db_one`.* TO 'alice'@'localhost'\n") - allow(described_class).to receive(:mysql_caller).with("SHOW GRANTS FOR 'bob'@'localhost';", 'regular').and_return("GRANT INSERT ON `db_two`.* TO 'bob'@'localhost'\n") + expect(described_class).not_to receive(:users) + expect(described_class).to receive(:mysql_caller).with("SHOW GRANTS FOR 'alice'@'localhost';", 'regular').and_return("GRANT SELECT ON `db_one`.* TO 'alice'@'localhost'\n") + expect(described_class).not_to receive(:mysql_caller).with("SHOW GRANTS FOR 'bob'@'localhost';", 'regular') instances = described_class.instances(['alice@localhost']) - expect(described_class).not_to have_received(:users) - expect(described_class).to have_received(:mysql_caller).with("SHOW GRANTS FOR 'alice'@'localhost';", 'regular') - expect(described_class).not_to have_received(:mysql_caller).with("SHOW GRANTS FOR 'bob'@'localhost';", 'regular') expect(instances.map(&:name)).to eq(['alice@localhost/db_one.*']) end it 'falls back to full user scan when managed user list is empty' do allow(described_class).to receive(:newer_than).and_return(false) - allow(described_class).to receive(:users).and_return(['alice@localhost']) + expect(described_class).to receive(:users).and_return(['alice@localhost']) allow(described_class).to receive(:mysql_caller).with("SHOW GRANTS FOR 'alice'@'localhost';", 'regular').and_return("GRANT SELECT ON `db_one`.* TO 'alice'@'localhost'\n") instances = described_class.instances([]) - expect(described_class).to have_received(:users) expect(instances.map(&:name)).to eq(['alice@localhost/db_one.*']) end end @@ -45,17 +41,12 @@ alice_provider = instance_double(described_class, name: 'alice@localhost/db_one.*') bob_provider = instance_double(described_class, name: 'bob@localhost/db_one.*') - allow(described_class).to receive(:instances).with(['alice@localhost', 'bob@localhost']).and_return([alice_provider, bob_provider]) - allow(grant_one).to receive(:provider=) - allow(grant_two).to receive(:provider=) - allow(grant_three).to receive(:provider=) + expect(described_class).to receive(:instances).with(['alice@localhost', 'bob@localhost']).and_return([alice_provider, bob_provider]) + expect(grant_one).to receive(:provider=).with(alice_provider) + expect(grant_two).not_to receive(:provider=) + expect(grant_three).to receive(:provider=).with(bob_provider) described_class.prefetch(resources) - - expect(described_class).to have_received(:instances).with(['alice@localhost', 'bob@localhost']) - expect(grant_one).to have_received(:provider=).with(alice_provider) - expect(grant_two).not_to have_received(:provider=) - expect(grant_three).to have_received(:provider=).with(bob_provider) end end end diff --git a/spec/unit/puppet/provider/mysql_user/mysql_spec.rb b/spec/unit/puppet/provider/mysql_user/mysql_spec.rb index 8132991d2..68d41d0c3 100644 --- a/spec/unit/puppet/provider/mysql_user/mysql_spec.rb +++ b/spec/unit/puppet/provider/mysql_user/mysql_spec.rb @@ -170,7 +170,7 @@ end it 'queries only managed users when user list is provided' do - managed_users = ["joe@localhost", "o'reilly@localhost"] + managed_users = ['joe@localhost', "o'reilly@localhost"] user_query = "SELECT CONCAT(User, '@',Host) AS User FROM mysql.user WHERE HOST IS NOT NULL AND HOST != '' AND CONCAT(User, '@', Host) IN ('joe@localhost', 'o''reilly@localhost')" allow(provider.class).to receive(:mysql_caller).with(user_query, 'regular').and_return("joe@localhost\no'reilly@localhost") @@ -221,11 +221,10 @@ 'jane@localhost' => instance_double(Puppet::Type.type(:mysql_user)) } - allow(provider.class).to receive(:instances).with(['joe@localhost', 'jane@localhost']).and_return([]) - resources.values.each { |res| allow(res).to receive(:provider=) } + expect(provider.class).to receive(:instances).with(['joe@localhost', 'jane@localhost']).and_return([]) + resources.each_value { |res| allow(res).to receive(:provider=) } provider.class.prefetch(resources) - expect(provider.class).to have_received(:instances).with(['joe@localhost', 'jane@localhost']) end end