Skip to content

Commit

Permalink
Merge pull request #22607 from kbrock/capture_vim_performance_spec1
Browse files Browse the repository at this point in the history
Specs for Vim Performance States

(cherry picked from commit f63d508)
  • Loading branch information
Fryguy committed Jul 25, 2023
1 parent ee84b8a commit 80053a9
Show file tree
Hide file tree
Showing 3 changed files with 204 additions and 40 deletions.
71 changes: 51 additions & 20 deletions spec/lib/miq_preloader_spec.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
RSpec.describe MiqPreloader do
# implied vms (simple association)
let(:ems) { FactoryBot.create(:ems_infra).tap { |ems| FactoryBot.create_list(:vm, 2, :ext_management_system => ems) } }

# implied container_nodes (through association)
let(:image) do
FactoryBot.create(:container_image).tap do |image|
FactoryBot.create(
:container,
:container_image => image,
:container_group => FactoryBot.create(:container_group, :container_node => FactoryBot.create(:container_node))
)
end
end

describe ".preload" do
it "preloads once from an object" do
ems = FactoryBot.create(:ems_infra)
Expand Down Expand Up @@ -29,52 +43,72 @@
it "preloads with a relation (records is a relation)" do
ems = FactoryBot.create(:ems_infra)
FactoryBot.create_list(:vm, 2, :ext_management_system => ems)

emses = ExtManagementSystem.all.load
vms = Vm.where(:ems_id => emses.select(:id))

expect { preload(emses, :vms, vms) }.to make_database_queries(:count => 1)

expect { expect(emses.first.vms.size).to eq(2) }.not_to make_database_queries
end

it "preloads with a loaded relation (records is a relation)" do
ems = FactoryBot.create(:ems_infra)
FactoryBot.create_list(:vm, 2, :ext_management_system => ems)
# original behavior - not calling our code
it "preloads with an unloaded simple relation" do
vms = Vm.where(:ems_id => ems.id)
vms2 = vms.order(:id).to_a # preloaded vms to be used in tests

# there is a query for every ems
expect { preload(ems, :vms, vms) }.to make_database_queries(:count => 1)
expect { preload(ems, :vms, vms) }.not_to make_database_queries
expect { expect(ems.vms).to match_array(vms2) }.not_to make_database_queries
# vms does not get loaded, so it is not preloaded
expect { expect(vms.first.ext_management_system).to eq(ems) }.to make_database_queries(:count => 2)
end

it "preloads with a loaded relation (records is a relation)" do
ems
emses = ExtManagementSystem.all.load
vms = Vm.where(:ems_id => emses.select(:id)).load

expect { preload(emses, :vms, vms) }.not_to make_database_queries

expect { preload(emses, :vms, vms) }.not_to make_database_queries
expect { expect(emses.first.vms.size).to eq(2) }.not_to make_database_queries
expect { expect(vms.first.ext_management_system).to eq(ems) }.not_to make_database_queries
end

it "preloads with an array (records is a relation)" do
ems = FactoryBot.create(:ems_infra)
FactoryBot.create_list(:vm, 2, :ext_management_system => ems)

ems
emses = ExtManagementSystem.all.load
vms = Vm.where(:ems_id => emses.select(:id)).to_a

expect { preload(emses, :vms, vms) }.not_to make_database_queries

expect { preload(emses, :vms, vms) }.not_to make_database_queries
expect { expect(emses.first.vms.size).to eq(2) }.not_to make_database_queries
expect { expect(vms.first.ext_management_system).to eq(ems) }.not_to make_database_queries
end

it "preloads with an array (records is an array)" do
ems = FactoryBot.create(:ems_infra)
FactoryBot.create_list(:vm, 2, :ext_management_system => ems)

ems
emses = ExtManagementSystem.all.load.to_a
vms = Vm.where(:ems_id => emses.map(&:id)).to_a

expect { preload(emses, :vms, vms) }.not_to make_database_queries

expect { preload(emses, :vms, vms) }.not_to make_database_queries
expect { expect(emses.first.vms.size).to eq(2) }.not_to make_database_queries
expect { expect(vms.first.ext_management_system).to eq(ems) }.not_to make_database_queries
end

it "preloads a through with a loaded scope" do
image
nodes = ContainerNode.all.load

# NOTE: it currently ignores the locally loaded records
# TODO: not_to make_database_queries
expect { preload(image, :container_nodes, nodes) }.to make_database_queries(:count => 3)
expect { preload(image, :container_nodes, nodes) }.not_to make_database_queries
expect { expect(image.container_nodes).to eq(nodes) }.not_to make_database_queries
# TODO: not_to make_database_queries
expect { expect(nodes.first.container_images).to eq([image]) }.to make_database_queries(:count => 1)
end

def preload(*args)
MiqPreloader.preload(*args)
end
Expand All @@ -84,9 +118,9 @@ def preload(*args)
it "preloads from an object" do
ems = FactoryBot.create(:ems_infra)
FactoryBot.create_list(:vm, 2, :ext_management_system => ems)

vms = nil
expect { vms = preload_and_map(ems, :vms) }.to make_database_queries(:count => 1)

expect { expect(vms.size).to eq(2) }.not_to make_database_queries
end

Expand Down Expand Up @@ -147,12 +181,9 @@ def preload_and_map(*args)
it "preloads (object.all).belongs_to.has_many" do
ems = FactoryBot.create(:ems_infra)
host = FactoryBot.create(:host, :ext_management_system => ems)
FactoryBot.create_list(:vm, 2,
:ext_management_system => ems,
:host => host)
FactoryBot.create_list(:vm, 2, :ext_management_system => ems, :host => host)
host = FactoryBot.create(:host, :ext_management_system => ems)
FactoryBot.create(:vm, :ext_management_system => ems,
:host => host)
FactoryBot.create(:vm, :ext_management_system => ems, :host => host)

emses = nil
vms = nil
Expand Down
130 changes: 130 additions & 0 deletions spec/models/metric/ci_mixin/state_finders_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
RSpec.describe Metric::CiMixin::StateFinders do
let(:image) { FactoryBot.create(:container_image) }
let(:container1) { FactoryBot.create(:container, :container_image => image) }
let(:container2) { FactoryBot.create(:container, :container_image => image) }
let(:node1) { FactoryBot.create(:container_node) }
let(:node2) { FactoryBot.create(:container_node) }

let(:ts_now) { Time.now.utc.beginning_of_hour.to_s }
let(:timestamp) { 2.hours.ago.utc.beginning_of_hour.to_s }

# NOTE: in these specs, we could let perf_capture_state be called
# but using this reduces the queries
describe "#vim_performance_state_for_ts" do
let(:vps_now) { create_vps(image, ts_now) }
let(:vps) { create_vps(image, timestamp) }

context "when no cache" do
it "creates new value when one is not found in the database" do
expect(image).to receive(:perf_capture_state).once.and_return(vps_now)

expect do
expect(image.vim_performance_state_for_ts(timestamp)).to eq(vps_now)
end.to make_database_queries(:count => 1)

# reuses cached / created value
expect do
expect(image.vim_performance_state_for_ts(timestamp)).to eq(vps_now)
end.not_to make_database_queries
end

it "caches the newly created value" do
expect(image).to receive(:perf_capture_state).once.and_return(vps_now)

image.vim_performance_state_for_ts(timestamp)
expect do
expect(image.vim_performance_state_for_ts(timestamp)).to eq(vps_now)
end.not_to make_database_queries
end
end

# ci_mixin/processing.rb uses this
context "when using preload_vim_performance_state_for_ts_iso8601" do
it "finds cached value" do
vps_now
vps
image.preload_vim_performance_state_for_ts_iso8601(:timestamp => [ts_now, timestamp])
expect(image).to receive(:perf_capture_state).never

expect do
expect(image.vim_performance_state_for_ts(timestamp)).to eq(vps_now) # TODO: should be vps
end.to make_database_queries(:count => 0)
end

it "falls back to cached now" do
vps_now
image.preload_vim_performance_state_for_ts_iso8601(:timestamp => [ts_now, timestamp])
expect(image).to receive(:perf_capture_state).never

expect do
expect(image.vim_performance_state_for_ts(timestamp)).to eq(vps_now)
end.not_to make_database_queries
end

it "creates (and caches) a value when now isn't cached" do
image.preload_vim_performance_state_for_ts_iso8601(:timestamp => [])
expect(image).to receive(:perf_capture_state).once.and_return(vps_now)

# NOTE: this performs a query because the back end does not know if this
# value was searched and not found, or no caching was performed
expect do
expect(image.vim_performance_state_for_ts(timestamp)).to eq(vps_now)
end.to make_database_queries(:count => 1)
expect { image.vim_performance_state_for_ts(timestamp) }.not_to make_database_queries
end
end

# ci_mixin/rollup.rb uses this
context "when using preload" do
it "finds cached value" do
vps_now
vps
rec_states = VimPerformanceState.where(:timestamp => [ts_now, timestamp])
MiqPreloader.preload(image, :vim_performance_states, rec_states)
expect(image).to receive(:perf_capture_state).never

expect do
expect(image.vim_performance_state_for_ts(timestamp)).to eq(vps)
end.not_to make_database_queries
end

it "falls back to cached now" do
vps_now
rec_states = VimPerformanceState.where(:timestamp => [ts_now, timestamp])
MiqPreloader.preload(image, :vim_performance_states, rec_states)
expect(image).to receive(:perf_capture_state).never

expect do
expect(image.vim_performance_state_for_ts(timestamp)).to eq(vps_now)
end.not_to make_database_queries
end

it "creates (and caches) a value when now isn't cached" do
rec_states = VimPerformanceState.where(:timestamp => [ts_now, timestamp])
MiqPreloader.preload(image, :vim_performance_states, rec_states)
expect(image).to receive(:perf_capture_state).twice.and_return(vps_now) # fix

expect do
expect(image.vim_performance_state_for_ts(timestamp)).to eq(vps_now)
end.not_to make_database_queries
expect { image.vim_performance_state_for_ts(timestamp) }.not_to make_database_queries
end
end
end

private

def create_vps(image, ts, containers = [], nodes = [])
FactoryBot.create(
:vim_performance_state,
:resource => image,
:timestamp => ts,
:state_data => {
:assoc_ids => {
:containers => {:on => containers.map(&:id), :off => []},
:container_nodes => {:on => nodes.map(&:id), :off => []},
}
}
)
end
end
43 changes: 23 additions & 20 deletions spec/models/vim_performance_state_spec.rb
Original file line number Diff line number Diff line change
@@ -1,22 +1,11 @@
RSpec.describe VimPerformanceState do
describe ".capture_host_sockets" do
it "returns the host sockets when given a host" do
hardware = FactoryBot.build(:hardware, :cpu_sockets => 2)
host = FactoryBot.create(:host, :hardware => hardware)
describe ".capture" do
it "uses now" do
host = FactoryBot.create(:host)
state = VimPerformanceState.capture(host)

expect(state.host_sockets).to eq(2)
end

it "rolls up the total sockets when given something that has hosts" do
hardware_1 = FactoryBot.build(:hardware, :cpu_sockets => 2)
hardware_2 = FactoryBot.build(:hardware, :cpu_sockets => 4)
host_1 = FactoryBot.build(:host, :hardware => hardware_1)
host_2 = FactoryBot.build(:host, :hardware => hardware_2)
cluster = FactoryBot.create(:ems_cluster, :hosts => [host_1, host_2])
state = VimPerformanceState.capture(cluster)

expect(state.host_sockets).to eq(6)
expect(state.timestamp).to be_within(1.minute).of(Time.now.utc.beginning_of_hour)
expect(state.capture_interval).to eq(3600) # 1.hour
end
end

Expand All @@ -37,10 +26,24 @@
end

describe "#host_sockets" do
it "returns the host sockets" do
state_data = {:host_sockets => 2}
actual = described_class.new(:state_data => state_data)
expect(actual.host_sockets).to eq(2)
it "captures the host sockets when given a host" do
hardware = FactoryBot.create(:hardware, :cpu_sockets => 2)
host = FactoryBot.create(:host, :hardware => hardware)
state = VimPerformanceState.capture(host)

expect(state.state_data).to include(:host_sockets => 2)
expect(state.host_sockets).to eq(2)
end

it "captures the rolled up sockets when given a cluster" do
hardware_1 = FactoryBot.build(:hardware, :cpu_sockets => 2)
hardware_2 = FactoryBot.build(:hardware, :cpu_sockets => 4)
host_1 = FactoryBot.build(:host, :hardware => hardware_1)
host_2 = FactoryBot.build(:host, :hardware => hardware_2)
cluster = FactoryBot.create(:ems_cluster, :hosts => [host_1, host_2])
state = VimPerformanceState.capture(cluster)

expect(state.host_sockets).to eq(6)
end
end

Expand Down

0 comments on commit 80053a9

Please sign in to comment.