vmpooler/spec/unit/api/helpers_spec.rb
2020-05-28 10:42:47 -07:00

532 lines
21 KiB
Ruby

require 'spec_helper'
require 'net/ldap'
# A class for testing purposes that includes the Helpers.
# this is impersonating V1's `helpers do include Helpers end`
#
# This is the subject used throughout the test file.
#
class TestHelpers
include Vmpooler::API::Helpers
end
describe Vmpooler::API::Helpers do
subject { TestHelpers.new }
describe '#hostname_shorten' do
[
['example.com', 'not-example.com', 'example.com'],
['example.com', 'example.com', 'example.com'],
['sub.example.com', 'example.com', 'sub'],
['adjective-noun.example.com', 'example.com', 'adjective-noun'],
['abc123.example.com', 'example.com', 'abc123'],
['example.com', nil, 'example.com']
].each do |hostname, domain, expected|
it { expect(subject.hostname_shorten(hostname, domain)).to eq expected }
end
end
describe '#validate_date_str' do
[
['2015-01-01', true],
[nil, false],
[false, false],
[true, false],
['01-01-2015', false],
['1/1/2015', false]
].each do |date, expected|
it { expect(subject.validate_date_str(date)).to eq expected }
end
end
describe '#mean' do
[
[[1, 2, 3, 4], 2.5],
[[1], 1],
[[nil], 0],
[[], 0]
].each do |list, expected|
it "returns #{expected.inspect} for #{list.inspect}" do
expect(subject.mean(list)).to eq expected
end
end
end
describe '#get_task_times' do
let(:redis) { double('redis') }
[
['task1', '2014-01-01', [1, 2, 3, 4], [1.0, 2.0, 3.0, 4.0]],
['task1', 'some date', [], []],
['task1', 'date', [2.2], [2.2]],
['task1', 'date', [2.2, 3, 3.0], [2.2, 3.0, 3.0]]
].each do |task, date, time_list, expected|
it "returns #{expected.inspect} for task #{task.inspect}@#{date.inspect}" do
allow(redis).to receive(:hvals).and_return time_list
expect(subject.get_task_times(redis, task, date)).to eq expected
end
end
end
describe '#get_capacity_metrics' do
let(:redis) { double('redis') }
let(:backend) { double('backend') }
it 'adds up pools correctly' do
pools = [
{'name' => 'p1', 'size' => 5},
{'name' => 'p2', 'size' => 5}
]
allow(redis).to receive(:pipelined).with(no_args).and_return [1,1]
expect(subject.get_capacity_metrics(pools, redis)).to eq({current: 2, total: 10, percent: 20.0})
end
it 'handles 0 from redis' do
pools = [
{'name' => 'p1', 'size' => 5},
{'name' => 'p2', 'size' => 5}
]
allow(redis).to receive(:pipelined).with(no_args).and_return [1,0]
expect(subject.get_capacity_metrics(pools, redis)).to eq({current: 1, total: 10, percent: 10.0})
end
it 'handles 0 size' do
pools = [
{'name' => 'p1', 'size' => 5},
{'name' => 'p2', 'size' => 0}
]
allow(redis).to receive(:pipelined).with(no_args).and_return [1,0]
expect(subject.get_capacity_metrics(pools, redis)).to eq({current: 1, total: 5, percent: 20.0})
end
it 'handles empty pool array' do
allow(redis).to receive(:pipelined).with(no_args).and_return []
expect(subject.get_capacity_metrics([], redis)).to eq({current: 0, total: 0, percent: 0})
end
end
describe '#get_queue_metrics' do
let(:redis) { double('redis') }
it 'handles empty pool array' do
allow(redis).to receive(:pipelined).with(no_args).and_return [0]
allow(redis).to receive(:get).and_return 0
expect(subject.get_queue_metrics([], redis)).to eq({pending: 0, cloning: 0, booting: 0, ready: 0, running: 0, completed: 0, total: 0})
end
it 'adds pool queues correctly' do
pools = [
{'name' => 'p1'},
{'name' => 'p2'}
]
allow(redis).to receive(:pipelined).with(no_args).and_return [1,1]
allow(redis).to receive(:get).and_return 1
expect(subject.get_queue_metrics(pools, redis)).to eq({pending: 2, cloning: 1, booting: 1, ready: 2, running: 2, completed: 2, total: 8})
end
it 'sets booting to 0 when negative calculation' do
pools = [
{'name' => 'p1'},
{'name' => 'p2'}
]
allow(redis).to receive(:pipelined).with(no_args).and_return [1,1]
allow(redis).to receive(:get).and_return 5
expect(subject.get_queue_metrics(pools, redis)).to eq({pending: 2, cloning: 5, booting: 0, ready: 2, running: 2, completed: 2, total: 8})
end
end
describe '#get_tag_metrics' do
let(:redis) { double('redis') }
it 'returns basic tag metrics' do
allow(redis).to receive(:hgetall).with('vmpooler__tag__2015-01-01').and_return({"abcdefghijklmno:tag" => "value"})
expect(subject.get_tag_metrics(redis, '2015-01-01')).to eq({"tag" => {"value"=>1, "total"=>1}})
end
it 'calculates tag totals' do
allow(redis).to receive(:hgetall).with('vmpooler__tag__2015-01-01').and_return({"abcdefghijklmno:tag" => "value", "pqrstuvwxyz12345:tag" => "another_value"})
expect(subject.get_tag_metrics(redis, '2015-01-01')).to eq({"tag"=>{"value"=>1, "total"=>2, "another_value"=>1}})
end
end
describe '#pool_index' do
let(:pools) {
[
{
'name' => 'pool1'
},
{
'name' => 'pool2'
}
]
}
it 'should return a hash' do
pools_hash = subject.pool_index(pools)
expect(pools_hash).to be_a(Hash)
end
it 'should return the correct index for each pool' do
pools_hash = subject.pool_index(pools)
expect(pools[pools_hash['pool1']]['name']).to eq('pool1')
expect(pools[pools_hash['pool2']]['name']).to eq('pool2')
end
end
describe '#template_ready?' do
let(:redis) { double('redis') }
let(:template) { 'template/test1' }
let(:poolname) { 'pool1' }
let(:pool) {
{
'name' => poolname,
'template' => template
}
}
it 'returns false when there is no prepared template' do
expect(redis).to receive(:hget).with('vmpooler__template__prepared', poolname).and_return(nil)
expect(subject.template_ready?(pool, redis)).to be false
end
it 'returns true when configured and prepared templates match' do
expect(redis).to receive(:hget).with('vmpooler__template__prepared', poolname).and_return(template)
expect(subject.template_ready?(pool, redis)).to be true
end
it 'returns false when configured and prepared templates do not match' do
expect(redis).to receive(:hget).with('vmpooler__template__prepared', poolname).and_return('template3')
expect(subject.template_ready?(pool, redis)).to be false
end
end
describe '#is_integer?' do
it 'returns true when input is an integer' do
expect(subject.is_integer? 4).to be true
end
it 'returns true when input is a string containing an integer' do
expect(subject.is_integer? '4').to be true
end
it 'returns false when input is a string containing word characters' do
expect(subject.is_integer? 'four').to be false
end
end
describe '#authenticate' do
let(:username_str) { 'admin' }
let(:password_str) { 's3cr3t' }
context 'with dummy provider' do
let(:auth) {
{
'provider': 'dummy'
}
}
it 'should return true' do
expect(subject).to receive(:authenticate).with(auth, username_str, password_str).and_return(true)
subject.authenticate(auth, username_str, password_str)
end
end
context 'with ldap provider' do
let(:host) { 'ldap.example.com' }
let(:base) { 'ou=user,dc=test,dc=com' }
let(:user_object) { 'uid' }
let(:auth) {
{
'provider' => 'ldap',
ldap: {
'host' => host,
'base' => base,
'user_object' => user_object
}
}
}
let(:default_port) { 389 }
it 'should attempt ldap authentication' do
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base, username_str, password_str)
subject.authenticate(auth, username_str, password_str)
end
it 'should return true when authentication is successful' do
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base, username_str, password_str).and_return(true)
expect(subject.authenticate(auth, username_str, password_str)).to be true
end
it 'should return false when authentication fails' do
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base, username_str, password_str).and_return(false)
expect(subject.authenticate(auth, username_str, password_str)).to be false
end
context 'with an alternate port' do
let(:alternate_port) { 636 }
before(:each) do
auth[:ldap]['port'] = alternate_port
end
it 'should specify the alternate port when authenticating' do
expect(subject).to receive(:authenticate_ldap).with(alternate_port, host, user_object, base, username_str, password_str)
subject.authenticate(auth, username_str, password_str)
end
end
context 'with multiple search bases' do
let(:base) {
[
'ou=user,dc=test,dc=com',
'ou=service,ou=user,dc=test,dc=com'
]
}
before(:each) do
auth[:ldap]['base'] = base
end
it 'should attempt to bind with each base' do
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base[0], username_str, password_str)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base[1], username_str, password_str)
subject.authenticate(auth, username_str, password_str)
end
it 'should not search the second base when the first binds' do
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base[0], username_str, password_str).and_return(true)
expect(subject).to_not receive(:authenticate_ldap).with(default_port, host, user_object, base[1], username_str, password_str)
subject.authenticate(auth, username_str, password_str)
end
it 'should search the second base when the first bind fails' do
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base[0], username_str, password_str).and_return(false)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base[1], username_str, password_str)
subject.authenticate(auth, username_str, password_str)
end
it 'should return true when any bind succeeds' do
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base[0], username_str, password_str).and_return(false)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base[1], username_str, password_str).and_return(true)
expect(subject.authenticate(auth, username_str, password_str)).to be true
end
it 'should return false when all bind attempts fail' do
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base[0], username_str, password_str).and_return(false)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base[1], username_str, password_str).and_return(false)
expect(subject.authenticate(auth, username_str, password_str)).to be false
end
end
context 'with multiple search user objects' do
let(:user_object) {
[
'uid',
'cn'
]
}
before(:each) do
auth[:ldap]['user_object'] = user_object
end
it 'should attempt to bind with each user object' do
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[0], base, username_str, password_str)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[1], base, username_str, password_str)
subject.authenticate(auth, username_str, password_str)
end
it 'should not search the second user object when the first binds' do
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[0], base, username_str, password_str).and_return(true)
expect(subject).to_not receive(:authenticate_ldap).with(default_port, host, user_object[1], base, username_str, password_str)
subject.authenticate(auth, username_str, password_str)
end
it 'should search the second user object when the first bind fails' do
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[0], base, username_str, password_str).and_return(false)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[1], base, username_str, password_str)
subject.authenticate(auth, username_str, password_str)
end
it 'should return true when any bind succeeds' do
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[0], base, username_str, password_str).and_return(false)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[1], base, username_str, password_str).and_return(true)
expect(subject.authenticate(auth, username_str, password_str)).to be true
end
it 'should return false when all bind attempts fail' do
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[0], base, username_str, password_str).and_return(false)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[1], base, username_str, password_str).and_return(false)
expect(subject.authenticate(auth, username_str, password_str)).to be false
end
end
context 'with multiple search user objects and with multiple search bases' do
let(:user_object) {
[
'uid',
'cn'
]
}
let(:base) {
[
'ou=user,dc=test,dc=com',
'ou=service,ou=user,dc=test,dc=com'
]
}
before(:each) do
auth[:ldap]['base'] = base
auth[:ldap]['user_object'] = user_object
end
it 'should attempt to bind with each user object and base' do
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[0], base[0], username_str, password_str)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[1], base[0], username_str, password_str)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[0], base[1], username_str, password_str)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[1], base[1], username_str, password_str)
subject.authenticate(auth, username_str, password_str)
end
it 'should not continue searching when the first combination binds' do
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[0], base[0], username_str, password_str).and_return(true)
expect(subject).to_not receive(:authenticate_ldap).with(default_port, host, user_object[1], base[0], username_str, password_str)
expect(subject).to_not receive(:authenticate_ldap).with(default_port, host, user_object[0], base[1], username_str, password_str)
expect(subject).to_not receive(:authenticate_ldap).with(default_port, host, user_object[1], base[1], username_str, password_str)
subject.authenticate(auth, username_str, password_str)
end
it 'should search the remaining combinations when the first bind fails' do
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[0], base[0], username_str, password_str).and_return(false)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[1], base[0], username_str, password_str)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[0], base[1], username_str, password_str)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[1], base[1], username_str, password_str)
subject.authenticate(auth, username_str, password_str)
end
it 'should search the remaining combinations when the first two binds fail' do
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[0], base[0], username_str, password_str).and_return(false)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[1], base[0], username_str, password_str).and_return(false)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[0], base[1], username_str, password_str)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[1], base[1], username_str, password_str)
subject.authenticate(auth, username_str, password_str)
end
it 'should search the remaining combination when the first three binds fail' do
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[0], base[0], username_str, password_str).and_return(false)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[1], base[0], username_str, password_str).and_return(false)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[0], base[1], username_str, password_str).and_return(false)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[1], base[1], username_str, password_str)
subject.authenticate(auth, username_str, password_str)
end
it 'should return true when any bind succeeds' do
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[0], base[0], username_str, password_str).and_return(false)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[1], base[0], username_str, password_str).and_return(false)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[0], base[1], username_str, password_str).and_return(false)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[1], base[1], username_str, password_str).and_return(true)
expect(subject.authenticate(auth, username_str, password_str)).to be true
end
it 'should return false when all bind attempts fail' do
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[0], base[0], username_str, password_str).and_return(false)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[1], base[0], username_str, password_str).and_return(false)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[0], base[1], username_str, password_str).and_return(false)
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object[1], base[1], username_str, password_str).and_return(false)
expect(subject.authenticate(auth, username_str, password_str)).to be false
end
end
end
context 'with unknown provider' do
let(:auth) {
{
'provider': 'mystery'
}
}
it 'should return false' do
expect(subject).to receive(:authenticate).with(auth, username_str, password_str).and_return(false)
subject.authenticate(auth, username_str, password_str)
end
end
end
describe '#authenticate_ldap' do
let(:port) { 389 }
let(:host) { 'ldap.example.com' }
let(:user_object) { 'uid' }
let(:base) { 'ou=users,dc=example,dc=com' }
let(:username_str) { 'admin' }
let(:password_str) { 's3cr3t' }
let(:ldap) { double('ldap') }
it 'should create a new ldap connection' do
allow(ldap).to receive(:bind)
expect(Net::LDAP).to receive(:new).with(
:host => host,
:port => port,
:encryption => {
:method => :start_tls,
:tls_options => { :ssl_version => 'TLSv1' }
},
:base => base,
:auth => {
:method => :simple,
:username => "#{user_object}=#{username_str},#{base}",
:password => password_str
}
).and_return(ldap)
subject.authenticate_ldap(port, host, user_object, base, username_str, password_str)
end
it 'should return true when a bind is successful' do
expect(Net::LDAP).to receive(:new).and_return(ldap)
expect(ldap).to receive(:bind).and_return(true)
expect(subject.authenticate_ldap(port, host, user_object, base, username_str, password_str)).to be true
end
it 'should return false when a bind fails' do
expect(Net::LDAP).to receive(:new).and_return(ldap)
expect(ldap).to receive(:bind).and_return(false)
expect(subject.authenticate_ldap(port, host, user_object, base, username_str, password_str)).to be false
end
end
end