Skip to content

Commit

Permalink
Add remaining specs; minor refactoring and improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
ikapelyukhin committed Apr 4, 2018
1 parent 8a9a024 commit a6f5cda
Show file tree
Hide file tree
Showing 15 changed files with 370 additions and 31 deletions.
7 changes: 4 additions & 3 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2018-04-04 10:08:10 +0200 using RuboCop version 0.52.1.
# on 2018-04-04 15:19:02 +0200 using RuboCop version 0.52.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.

# Offense count: 1
# Offense count: 2
# Configuration parameters: Max.
RSpec/ExampleLength:
Exclude:
- 'spec/features/**/*'
- 'spec/rmt/ssl/certificate_generator_spec.rb'
- 'spec/rmt/wizard_ssl_page_spec.rb'

# Offense count: 152
# Offense count: 207
# Configuration parameters: .
# SupportedStyles: have_received, receive
RSpec/MessageSpies:
Expand Down
55 changes: 55 additions & 0 deletions spec/rmt/execute_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Copyright (c) 2018 SUSE LLC.
# All Rights Reserved.

# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 or 3 of the GNU General
# Public License as published by the Free Software Foundation.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, contact SUSE LLC.

# To contact SUSE about this file by physical or electronic mail,
# you may find current contact information at www.suse.com

require 'rmt/execute'

Yast.import 'Report'

describe RMT::Execute do
describe '.on_target' do
let(:exit_double) { instance_double(Process::Status) }

it 'executes the command' do
expect(described_class).to receive(:on_target!)
described_class.on_target
end

it 'shows an error message when an exception ocurrs' do
expect(exit_double).to receive(:exitstatus).and_return(255)
expect(described_class).to receive(:on_target!).and_raise(Cheetah::ExecutionFailed.new('command', exit_double, '', 'Something went wrong'))
expect(Yast::Report).to receive(:Error)
described_class.on_target
end
end

describe '.on_target!' do
let(:chroot) { '/tmp' }

it 'appends chroot and runs command when args item is not a hash' do
expect(Yast::WFM).to receive(:scr_root).and_return(chroot)
expect(Cheetah).to receive(:run).with('cmd', { chroot: chroot })
described_class.on_target!('cmd')
end

it 'appends chroot and runs command when args item is a hash' do
expect(Yast::WFM).to receive(:scr_root).and_return(chroot)
expect(Cheetah).to receive(:run).with('cmd', { foo: 'bar', chroot: chroot })
described_class.on_target!('cmd', { foo: 'bar' })
end
end
end
64 changes: 64 additions & 0 deletions spec/rmt/ssl/alternative_common_name_dialog_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Copyright (c) 2018 SUSE LLC.
# All Rights Reserved.

# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 or 3 of the GNU General
# Public License as published by the Free Software Foundation.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, contact SUSE LLC.

# To contact SUSE about this file by physical or electronic mail,
# you may find current contact information at www.suse.com

require 'rmt/ssl/alternative_common_name_dialog'

Yast.import 'Report'

describe RMT::SSL::AlternativeCommonNameDialog do
subject(:dialog) { described_class.new }

describe '#dialog_content' do
it 'creates the UI elements' do
expect(Yast::Term).to receive(:new).exactly(22).times
dialog.dialog_content
end
end

describe '#user_input' do
it 'sets focus and waits for user input' do
expect(Yast::UI).to receive(:SetFocus).with(Id(:alt_name))
expect_any_instance_of(UI::Dialog).to receive(:user_input)
dialog.user_input
end
end

describe '#ok_handler' do
context 'when the alt name field is empty' do
let(:alt_name) { '' }

it 'reports an error' do
expect(Yast::UI).to receive(:QueryWidget).with(Id(:alt_name), :Value).and_return(alt_name)
expect(Yast::UI).to receive(:SetFocus).with(Id(:alt_name))
expect(Yast::Report).to receive(:Error).with('Alternative common name must not be empty.')
expect(dialog).not_to receive(:finish_dialog)
dialog.ok_handler
end
end

context 'when the alt name field is not empty' do
let(:alt_name) { 'example.org' }

it 'finishes the dialog and returns the alt name' do
expect(Yast::UI).to receive(:QueryWidget).with(Id(:alt_name), :Value).and_return(alt_name)
expect(dialog).to receive(:finish_dialog).with(alt_name)
dialog.ok_handler
end
end
end
end
161 changes: 161 additions & 0 deletions spec/rmt/ssl/certificate_generator_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# Copyright (c) 2018 SUSE LLC.
# All Rights Reserved.

# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 or 3 of the GNU General
# Public License as published by the Free Software Foundation.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, contact SUSE LLC.

# To contact SUSE about this file by physical or electronic mail,
# you may find current contact information at www.suse.com

require 'rmt/ssl/certificate_generator'

Yast.import 'Report'

describe RMT::SSL::CertificateGenerator do
subject(:generator) { described_class.new }

let(:ssl_files) do
described_class::OPENSSL_FILES.map { |id, filename| [id, File.join(described_class::RMT_SSL_DIR, filename)] }.to_h
end

let(:crt_and_key_files) { %i[ca_private_key ca_certificate server_private_key server_certificate] }

describe '#check_certs_presence' do
subject(:result) { generator.check_certs_presence }

before do
# Yast reads locale data at startup for i18n
expect(File).to receive(:exist?).with('/usr/share/YaST2/locale').and_return(false)
end

it 'returns false when none of the files exist' do
crt_and_key_files.each do |file|
expect(File).to receive(:exist?).with(ssl_files[file]).and_return(false)
end
expect(result).to eq(false)
end

it 'returns false when all of the files are empty' do
crt_and_key_files.each do |file|
expect(File).to receive(:exist?).with(ssl_files[file]).and_return(true)
expect(File).to receive(:zero?).with(ssl_files[file]).and_return(true)
end
expect(result).to eq(false)
end

it 'returns true when one the files exist and is not empty' do
file = crt_and_key_files.shift
expect(File).to receive(:exist?).with(ssl_files[file]).and_return(true)
expect(File).to receive(:zero?).with(ssl_files[file]).and_return(false)

expect(result).to eq(true)
end
end

describe '#generate' do
let(:scr_path) { Yast.path('.target.string') }
let(:config_generator_double) { instance_double(RMT::SSL::ConfigGenerator) }
let(:ca_config) { 'ca_config' }
let(:server_config) { 'server_config' }
let(:ca_cert) { 'ca_cert' }
let(:server_cert) { 'server_cert' }
let(:common_name) { 'example.org' }
let(:alt_names) { ['foo.example.org', 'bar.example.org'] }

it 'generates the certificate' do
expect(RMT::SSL::ConfigGenerator).to receive(:new).and_return(config_generator_double)
expect(config_generator_double).to receive(:make_ca_config) { ca_config }
expect(config_generator_double).to receive(:make_server_config) { server_config }

expect(generator).to receive(:create_files)

expect(Yast::SCR).to receive(:Write).with(scr_path, ssl_files[:ca_serial_file], '01')
expect(Yast::SCR).to receive(:Write).with(scr_path, ssl_files[:ca_config], ca_config)
expect(Yast::SCR).to receive(:Write).with(scr_path, ssl_files[:server_config], server_config)

expect(RMT::Execute).to receive(:on_target!).with(
'openssl', 'genrsa', '-out',
ssl_files[:ca_private_key], described_class::OPENSSL_KEY_BITS
)

expect(RMT::Execute).to receive(:on_target!).with(
'openssl', 'genrsa', '-out',
ssl_files[:server_private_key], described_class::OPENSSL_KEY_BITS
)

expect(RMT::Execute).to receive(:on_target!).with(
'openssl', 'req', '-x509', '-new', '-nodes',
'-key', ssl_files[:ca_private_key], '-sha256', '-days', described_class::OPENSSL_CA_VALIDITY_DAYS,
'-out', ssl_files[:ca_certificate], '-config', ssl_files[:ca_config]
)

expect(RMT::Execute).to receive(:on_target!).with(
'openssl', 'req', '-new', '-key', ssl_files[:server_private_key],
'-out', ssl_files[:server_csr], '-config', ssl_files[:server_config]
)

expect(RMT::Execute).to receive(:on_target!).with(
'openssl', 'x509', '-req', '-in', ssl_files[:server_csr],
'-out', ssl_files[:server_certificate], '-CA', ssl_files[:ca_certificate],
'-CAkey', ssl_files[:ca_private_key], '-days', described_class::OPENSSL_SERVER_CERT_VALIDITY_DAYS,
'-sha256', '-CAcreateserial', '-extensions', 'v3_server_sign',
'-extfile', ssl_files[:server_config]
)

expect(Yast::SCR).to receive(:Read).with(scr_path, ssl_files[:server_certificate]).and_return(server_cert)
expect(Yast::SCR).to receive(:Read).with(scr_path, ssl_files[:ca_certificate]).and_return(ca_cert)
expect(Yast::SCR).to receive(:Write).with(scr_path, ssl_files[:server_certificate], server_cert + ca_cert)

expect(RMT::Execute).to receive(:on_target!).with('chown', 'root:nginx', ssl_files[:ca_certificate])
expect(RMT::Execute).to receive(:on_target!).with('chmod', '0640', ssl_files[:ca_certificate])

generator.generate(common_name, alt_names)
end

it 'handles Cheetah::ExecutionFailed exceptions' do
expect(RMT::SSL::ConfigGenerator).to receive(:new).and_raise(Cheetah::ExecutionFailed.new('cmd', 1, '', 'Dummy error'))
expect(Yast::Report).to receive(:Error).with("An error ocurred during SSL certificate generation:\nDummy error\n")
generator.generate(common_name, alt_names)
end

it 'handles RMT::SSL::Exception exceptions' do
expect(RMT::SSL::ConfigGenerator).to receive(:new).and_raise(RMT::SSL::Exception.new('Dummy error'))
expect(Yast::Report).to receive(:Error).with("An error ocurred during SSL certificate generation:\nDummy error\n")
generator.generate(common_name, alt_names)
end
end

describe '#create_files' do
it 'creates empty files for openssl and sets permissions' do
ssl_files.each_value do |file|
expect(generator).to receive(:write_file).with(file, '')
expect(RMT::Execute).to receive(:on_target!).with('chmod', '0600', file)
end
generator.send(:create_files)
end
end

describe '#write_file' do
let(:filename) { '/tmp/test' }
let(:content) { 'test' }

it 'writes a file' do
expect(Yast::SCR).to receive(:Write).with(Yast.path('.target.string'), filename, content).and_return(true)
generator.send(:write_file, filename, content)
end

it 'raises and exception when write failed' do
expect(Yast::SCR).to receive(:Write).with(Yast.path('.target.string'), filename, content).and_return(false)
expect { generator.send(:write_file, filename, content) }.to raise_error(RMT::SSL::Exception, "Failed to write file #{filename}")
end
end
end
64 changes: 64 additions & 0 deletions spec/rmt/ssl/config_generator_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Copyright (c) 2018 SUSE LLC.
# All Rights Reserved.

# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 or 3 of the GNU General
# Public License as published by the Free Software Foundation.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, contact SUSE LLC.

# To contact SUSE about this file by physical or electronic mail,
# you may find current contact information at www.suse.com

require 'rmt/ssl/config_generator'

describe RMT::SSL::ConfigGenerator do
subject(:generator) { described_class.new(common_name, alt_names) }

let(:common_name) { 'example.org' }
let(:dns_names) { ['foo.example.org', 'bar.example.org'] }
let(:ip_addresses) { ['1.1.1.1', '1111:2222:3333:4444:5555:6666:7777:8888'] }
let(:alt_names) { dns_names + ip_addresses }

describe '#new' do
it 'matches DNS names' do
expect(generator.dns_alt_names).to eq([common_name] + dns_names)
end

it 'matches IP addresses' do
expect(generator.ip_alt_names).to eq(ip_addresses)
end
end

describe '#make_ca_config' do
it 'contains correct common name' do
expect(generator.make_ca_config).to match(/CN\s*=\s*RMT Certificate Authority \(#{common_name}\)/)
end
end

describe '#make_server_config' do
subject(:config) { generator.make_server_config }

it 'contains correct common name' do
expect(config).to match(/CN\s*=\s*#{common_name}/)
end

it 'contains DNS alternative common names' do
dns_names.each do |alt_name|
expect(config).to match(/DNS\.\d+\s*=\s*#{alt_name}/)
end
end

it 'contains IP alternative common names' do
ip_addresses.each do |alt_name|
expect(config).to match(/IP\.\d+\s*=\s*#{alt_name}/)
end
end
end
end
2 changes: 1 addition & 1 deletion spec/rmt/wizard_maria_db_page_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

describe '#render_content' do
it 'renders UI elements' do
expect(Yast::Wizard).to receive(:SetNextButton).with(:next, Yast::Label.OKButton)
expect(Yast::Wizard).to receive(:SetNextButton).with(:next, Yast::Label.NextButton)
expect(Yast::Wizard).to receive(:SetContents)

expect(Yast::UI).to receive(:ChangeWidget).with(Id(:db_username), :Value, config['database']['username'])
Expand Down
Loading

0 comments on commit a6f5cda

Please sign in to comment.