Introduce the concept of a single spec for the tests, we removed the platform depant test as they where mostly similar, but only used with small platform dependant metadata, this all has been moved to factory methods. make sure platforms uses canonicals "former" names, so no "ubuntu" platfrom as is debian based, and no "centos" as is redhat based.

Also:

* Refactored the specs organization to make the resoning behind simplier,
introducing the idea of an artifact subject that it wraps the
interactions with the platform.

* Add methods to destroy, bootstrap and halt a list of machines either all of them or the ones listed under a given platform name.

* Introduced more clear namespacing in the rakefile.

* Updated the list of available platforms for acceptance testing, including latest ubuntu, oel, fedora, debian and suse versions

Fixes #5350
This commit is contained in:
Pere Urbon-Bayes 2016-04-29 11:13:16 +02:00
parent 1c6f97b86a
commit ced5e5e020
26 changed files with 348 additions and 188 deletions

View file

@ -8,7 +8,7 @@ export JRUBY_OPTS="-J-Xmx1g"
SELECTED_TEST_SUITE=$1
if [[ $SELECTED_TEST_SUITE == $"centos" ]]; then
if [[ $SELECTED_TEST_SUITE == $"redhat" ]]; then
echo "Generating the RPM, make sure you start with a clean environment before generating other packages."
rake artifact:rpm
echo "Acceptance: Installing dependencies"
@ -16,9 +16,10 @@ if [[ $SELECTED_TEST_SUITE == $"centos" ]]; then
bundle install
echo "Acceptance: Running the tests"
bundle exec rake test:setup
bundle exec rake test:ssh_config
bundle exec rake test:acceptance:centos
bundle exec rake qa:vm:setup["redhat"]
bundle exec rake qa:vm:ssh_config
bundle exec rake qa:acceptance:redhat
bundle exec rake qa:vm:halt["redhat"]
elif [[ $SELECTED_TEST_SUITE == $"debian" ]]; then
echo "Generating the DEB, make sure you start with a clean environment before generating other packages."
rake artifact:deb
@ -27,9 +28,10 @@ elif [[ $SELECTED_TEST_SUITE == $"debian" ]]; then
bundle install
echo "Acceptance: Running the tests"
bundle exec rake test:setup
bundle exec rake test:ssh_config
bundle exec rake test:acceptance:debian
bundle exec rake qa:vm:setup["debian"]
bundle exec rake qa:vm:ssh_config
bundle exec rake qa:acceptance:debian
bundle exec rake qa:vm:halt["debian"]
elif [[ $SELECTED_TEST_SUITE == $"all" ]]; then
echo "Building Logstash artifacts"
rake artifact:all
@ -39,8 +41,9 @@ elif [[ $SELECTED_TEST_SUITE == $"all" ]]; then
bundle install
echo "Acceptance: Running the tests"
bundle exec rake test:setup
bundle exec rake test:ssh_config
bundle exec rake test:acceptance:all
bundle exec rake qa:vm:setup
bundle exec rake qa:vm:ssh_config
bundle exec rake qa:acceptance:all
bundle exec rake qa:vm:halt
cd ..
fi

View file

@ -2,3 +2,4 @@ source "https://rubygems.org"
gem "runner-tool", :git => "https://github.com/purbon/runner-tool.git"
gem "rspec", "~> 3.1.0"
gem "rake"
gem "pry", :group => :test

View file

@ -9,39 +9,61 @@ platforms = PlatformConfig.new
task :spec => 'spec:all'
task :default => :spec
namespace :test do
desc "Generate a valid ssh-config"
task :ssh_config do
require "json"
raw_ssh_config = LogStash::VagrantHelpers.fetch_config.stdout.split("\n");
parsed_ssh_config = LogStash::VagrantHelpers.parse(raw_ssh_config)
File.write(File.join(File.dirname(__FILE__), ".vm_ssh_config"), parsed_ssh_config.to_json)
end
namespace :qa do
desc "Bootstrap all the VM's used for this tests"
task "setup" do
puts "bootstraping all VM's defined in acceptance/Vagrantfile"
LogStash::VagrantHelpers.bootstrap
namespace :vm do
desc "Generate a valid ssh-config"
task :ssh_config do
require "json"
raw_ssh_config = LogStash::VagrantHelpers.fetch_config.stdout.split("\n");
parsed_ssh_config = LogStash::VagrantHelpers.parse(raw_ssh_config)
File.write(".vm_ssh_config", parsed_ssh_config.to_json)
end
desc "Bootstrap all the VM's used for this tests"
task :setup, :platform do |t, args|
config = PlatformConfig.new
machines = config.select_names_for(args[:platform])
message = "bootstraping all VM's defined in acceptance/Vagrantfile"
message = "#{message} for #{args[:platform]}: #{machines}" if !args[:platform].nil?
puts message
LogStash::VagrantHelpers.destroy(machines)
LogStash::VagrantHelpers.bootstrap(machines)
end
desc "Halt all VM's involved in the acceptance test round"
task :halt, :platform do |t, args|
config = PlatformConfig.new
machines = config.select_names_for(args[:platform])
message = "halting all VM's defined inside Vagrantfile"
message = "#{message} for #{args[:platform]}: #{machines}" if !args[:platform].nil?
puts message
LogStash::VagrantHelpers.halt(machines)
end
end
namespace :acceptance do
desc "Run all acceptance"
task :all do
exit(RSpec::Core::Runner.run([Rake::FileList["acceptance/spec/**/*_spec.rb"]]))
exit(RSpec::Core::Runner.run([Rake::FileList["acceptance/spec/lib/*_spec.rb"]]))
end
platforms.types.each do |type|
desc "Run acceptance test in #{type} machines"
task type do
exit(RSpec::Core::Runner.run([Rake::FileList["acceptance/spec/#{type}/**/*_spec.rb"]]))
ENV['LS_TEST_PLATFORM']=type
exit(RSpec::Core::Runner.run([Rake::FileList["acceptance/spec/lib/*_spec.rb"]]))
end
end
desc "Run one single machine acceptance test"
task :single, :machine do |t, args|
ENV['LS_VAGRANT_HOST'] = args[:machine]
platform = LogStash::VagrantHelpers.translate(args[:machine])
exit(RSpec::Core::Runner.run([Rake::FileList["acceptance/spec/**/*_spec.rb"]]))
task :single, :machine do |t, args|
ENV['LS_VAGRANT_HOST'] = args[:machine]
exit(RSpec::Core::Runner.run([Rake::FileList["acceptance/spec/lib/*_spec.rb"]]))
end
end
end

View file

@ -1,33 +0,0 @@
# encoding: utf-8
require_relative "../spec_helper"
require "logstash/version"
describe "artifacts", :platform => :centos do
shared_examples "installable" do |host, name|
before(:each) do
install("/logstash-build/logstash-#{LOGSTASH_VERSION}.noarch.rpm", host)
end
it "is installed on #{name}" do
expect("logstash").to be_installed.on(host)
end
it "is running in #{name}" do
start_service("logstash", host)
expect("logstash").to be_running.on(host)
stop_service("logstash", host)
end
it "is removable on #{name}" do
uninstall("logstash", host)
expect("logstash").to be_removed.on(host)
end
end
config = ServiceTester.configuration
config.servers.each do |host|
it_behaves_like "installable", host, config.lookup[host]
end
end

View file

@ -1,15 +0,0 @@
# encoding: utf-8
require_relative '../spec_helper'
def default_vagrant_boxes
[
"centos-6",
"centos-7"
]
end
selected_boxes = SpecsHelper.find_selected_boxes(default_vagrant_boxes)
SpecsHelper.configure(selected_boxes)
puts "[Acceptance specs] running on #{ServiceTester.configuration.lookup.values}" if !selected_boxes.empty?

View file

@ -3,25 +3,20 @@ require "json"
module SpecsHelper
def self.find_selected_boxes(default_boxes=[])
if ENV.include?('LS_VAGRANT_HOST') then
default_boxes.include?(ENV['LS_VAGRANT_HOST']) ? ENV['LS_VAGRANT_HOST'] : []
else
default_boxes
end
end
def self.configure(vagrant_boxes)
setup_config = JSON.parse(File.read(File.join(File.dirname(__FILE__), "..", "..", ".vm_ssh_config")))
boxes = vagrant_boxes.inject({}) do |acc, v|
acc[v.name] = v.type
acc
end
ServiceTester.configure do |config|
config.servers = []
config.lookup = {}
setup_config.each do |host_info|
next unless vagrant_boxes.include?(host_info["host"])
next unless boxes.keys.include?(host_info["host"])
url = "#{host_info["hostname"]}:#{host_info["port"]}"
config.servers << url
config.lookup[url] = host_info["host"]
config.lookup[url] = {"host" => host_info["host"], "type" => boxes[host_info["host"]] }
end
end
end

View file

@ -1,33 +0,0 @@
# encoding: utf-8
require_relative "../spec_helper"
require "logstash/version"
describe "artifacts", :platform => :debian do
shared_examples "installable" do |host, name|
before(:each) do
install("/logstash-build/logstash-#{LOGSTASH_VERSION}_all.deb", host)
end
it "is installed on #{name}" do
expect("logstash").to be_installed.on(host)
end
it "is running on #{name}" do
start_service("logstash", host)
expect("logstash").to be_running.on(host)
stop_service("logstash", host)
end
it "is removable on #{name}" do
uninstall("logstash", host)
expect("logstash").to be_removed.on(host)
end
end
config = ServiceTester.configuration
config.servers.each do |host|
it_behaves_like "installable", host, config.lookup[host]
end
end

View file

@ -1,15 +0,0 @@
# encoding: utf-8
require_relative '../spec_helper'
def default_vagrant_boxes
[
"ubuntu-1204",
"ubuntu-1404"
]
end
selected_boxes = SpecsHelper.find_selected_boxes(default_vagrant_boxes)
SpecsHelper.configure(selected_boxes)
puts "[Acceptance specs] running on #{ServiceTester.configuration.lookup.values}" if !selected_boxes.empty?

View file

@ -0,0 +1,13 @@
# encoding: utf-8
require_relative '../spec_helper'
require_relative '../shared_examples/installed'
require_relative '../shared_examples/running'
describe "artifacts operation" do
config = ServiceTester.configuration
config.servers.each do |address|
logstash = ServiceTester::Artifact.new(address, config.lookup[address])
it_behaves_like "installable", logstash
it_behaves_like "runnable", logstash
end
end

View file

@ -0,0 +1,24 @@
require_relative '../spec_helper'
require 'logstash/version'
RSpec.shared_examples "installable" do |logstash|
before(:each) do
logstash.install(LOGSTASH_VERSION)
end
it "is installed on #{logstash.host}" do
expect(logstash).to be_installed
end
it "is running on #{logstash.host}" do
logstash.start_service
expect(logstash).to be_running
logstash.stop_service
end
it "is removable on #{logstash.host}" do
logstash.uninstall
expect(logstash).to be_removed
end
end

View file

@ -0,0 +1,16 @@
require_relative '../spec_helper'
require 'logstash/version'
RSpec.shared_examples "runnable" do |logstash|
before(:each) do
logstash.install(LOGSTASH_VERSION)
end
it "is running on #{logstash.host}" do
logstash.start_service
expect(logstash).to be_running
logstash.stop_service
end
end

View file

@ -3,6 +3,7 @@ require 'runner-tool'
require_relative '../../rspec/helpers'
require_relative '../../rspec/matchers'
require_relative 'config_helper'
require_relative "../../platform_config"
ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..'))
$LOAD_PATH.unshift File.join(ROOT, 'logstash-core/lib')
@ -12,3 +13,18 @@ RunnerTool.configure
RSpec.configure do |c|
c.include ServiceTester
end
platform = ENV['LS_TEST_PLATFORM'] || 'all'
config = PlatformConfig.new
default_vagrant_boxes = ( platform == 'all' ? config.platforms : config.filter_type(platform) )
selected_boxes = if ENV.include?('LS_VAGRANT_HOST') then
config.platforms.select { |p| p.name == ENV['LS_VAGRANT_HOST'] }
else
default_vagrant_boxes
end
SpecsHelper.configure(selected_boxes)
puts "[Acceptance specs] running on #{ServiceTester.configuration.hosts}" if !selected_boxes.empty?

View file

@ -2,9 +2,12 @@
require "json"
class PlatformConfig
Platform = Struct.new(:name, :box, :type)
DEFAULT_CONFIG_LOCATION = File.join(File.dirname(__FILE__), "platforms.json")
DEFAULT_CONFIG_LOCATION = File.join(File.dirname(__FILE__), "platforms.json").freeze
attr_reader :platforms
def initialize(config_path = DEFAULT_CONFIG_LOCATION)
@config_path = config_path
@ -35,6 +38,10 @@ class PlatformConfig
@platforms.select { |platform| platform.type == type_name }
end
def select_names_for(platform=nil)
!platform.nil? ? filter_type(platform).map{ |p| p.name } : ""
end
def types
@platforms.collect(&:type).uniq.sort
end

View file

@ -1,6 +1,13 @@
{
"ubuntu-1204": { "box": "elastic/ubuntu-12.04-x86_64", "type": "debian" },
"ubuntu-1404": { "box": "elastic/ubuntu-14.04-x86_64", "type": "debian" },
"centos-6": { "box": "elastic/centos-6-x86_64", "type": "centos" },
"centos-7": { "box": "elastic/centos-7-x86_64", "type": "centos" }
"ubuntu-1504": { "box": "elastic/ubuntu-15.04-x86_64", "type": "debian" },
"centos-6": { "box": "elastic/centos-6-x86_64", "type": "redhat" },
"centos-7": { "box": "elastic/centos-7-x86_64", "type": "redhat" },
"oel-6": { "box": "elastic/oraclelinux-6-x86_64", "type": "redhat" },
"oel-7": { "box": "elastic/oraclelinux-7-x86_64", "type": "redhat" },
"fedora-22": { "box": "elastic/fedora-22-x86_64", "type": "redhat" },
"debian-8": { "box": "elastic/debian-8-x86_64", "type": "debian" },
"opensuse-13": { "box": "elastic/opensuse-13-x86_64", "type": "suse" },
"sles-12": { "box": "elastic/sles-12-x86_64", "type": "suse" }
}

View file

@ -1,16 +1,69 @@
# encoding: utf-8
require_relative "./debian/commands"
require_relative "./centos/commands"
require_relative "./commands/debian"
require_relative "./commands/ubuntu"
require_relative "./commands/redhat"
require_relative "./commands/suse"
require "forwardable"
module ServiceTester
class Artifact
extend Forwardable
def_delegators :@client, :installed?, :removed?, :running?
attr_reader :host, :client
def initialize(host, options={})
@host = host
@options = options
@client = CommandsFactory.fetch(options["type"], options["host"])
end
def name
"logstash"
end
def hosts
[@host]
end
def start_service
client.start_service(name, host)
end
def stop_service
client.stop_service(name, host)
end
def install(version)
package = client.package_for(version)
client.install(package, host)
end
def uninstall
client.uninstall(name, host)
end
def to_s
"Artifact #{name}@#{host}"
end
end
class CommandsFactory
def self.fetch(type)
def self.fetch(type, host)
case type
when :debian
return DebianCommands.new
when :centos
return CentosCommands.new
when "debian"
if host.start_with?("ubuntu")
return UbuntuCommands.new
else
return DebianCommands.new
end
when "suse"
return SuseCommands.new
when "redhat"
return RedhatCommands.new
else
return
end

18
qa/rspec/commands/base.rb Normal file
View file

@ -0,0 +1,18 @@
# encoding: utf-8
module ServiceTester
class Base
LOCATION="/logstash-build".freeze
def start_service(service, host=nil)
service_manager(service, "start", host)
end
def stop_service(service, host=nil)
service_manager(service, "stop", host)
end
end
end

View file

@ -1,6 +1,8 @@
# encoding: utf-8
require_relative "base"
module ServiceTester
class DebianCommands
class DebianCommands < Base
def installed?(hosts, package)
stdout = ""
@ -12,6 +14,10 @@ module ServiceTester
stdout.match(/^Status: install ok installed$/)
end
def package_for(version)
File.join(ServiceTester::Base::LOCATION, "logstash-#{version}_all.deb")
end
def install(package, host=nil)
hosts = (host.nil? ? servers : Array(host))
at(hosts, {in: :serial}) do |_|
@ -45,7 +51,7 @@ module ServiceTester
cmd = sudo_exec!("service #{package} status")
stdout = cmd.stdout
end
stdout.match(/^#{package} is running$/)
stdout.match(/#{package} started.$/)
end
def service_manager(service, action, host=nil)

View file

@ -1,6 +1,8 @@
# encoding: utf-8
require_relative "base"
module ServiceTester
class CentosCommands
class RedhatCommands < Base
def installed?(hosts, package)
stdout = ""
@ -12,6 +14,10 @@ module ServiceTester
stdout.match(/^logstash.noarch/)
end
def package_for(version)
File.join(ServiceTester::Base::LOCATION, "logstash-#{version}.noarch.rpm")
end
def install(package, host=nil)
hosts = (host.nil? ? servers : Array(host))
errors = {}
@ -49,7 +55,7 @@ module ServiceTester
def service_manager(service, action, host=nil)
hosts = (host.nil? ? servers : Array(host))
at(hosts, {in: :serial}) do |host|
at(hosts, {in: :serial}) do |_|
sudo_exec!("service #{service} #{action}")
end
end

63
qa/rspec/commands/suse.rb Normal file
View file

@ -0,0 +1,63 @@
# encoding: utf-8
require_relative "base"
module ServiceTester
class SuseCommands < Base
def installed?(hosts, package)
stdout = ""
at(hosts, {in: :serial}) do |host|
cmd = exec!("zypper search #{package}")
stdout = cmd.stdout
end
stdout.match(/^i | logstash | An extensible logging pipeline | package$/)
end
def package_for(version)
File.join(ServiceTester::Base::LOCATION, "logstash-#{version}.noarch.rpm")
end
def install(package, host=nil)
hosts = (host.nil? ? servers : Array(host))
errors = {}
at(hosts, {in: :serial}) do |_host|
cmd = sudo_exec!("zypper --no-gpg-checks --non-interactive install #{package}")
errors[_host] = cmd.stderr unless cmd.stderr.empty?
end
errors
end
def uninstall(package, host=nil)
hosts = (host.nil? ? servers : Array(host))
at(hosts, {in: :serial}) do |_|
cmd = sudo_exec!("zypper --no-gpg-checks --non-interactive remove #{package}")
end
end
def removed?(hosts, package)
stdout = ""
at(hosts, {in: :serial}) do |host|
cmd = exec!("zypper search #{package}")
stdout = cmd.stdout
end
stdout.match(/No packages found/)
end
def running?(hosts, package)
stdout = ""
at(hosts, {in: :serial}) do |host|
cmd = sudo_exec!("service #{package} status")
stdout = cmd.stdout
end
stdout.match(/#{package} started.$/)
end
def service_manager(service, action, host=nil)
hosts = (host.nil? ? servers : Array(host))
at(hosts, {in: :serial}) do |_|
sudo_exec!("service #{service} #{action}")
end
end
end
end

View file

@ -0,0 +1,17 @@
# encoding: utf-8
require_relative "debian"
module ServiceTester
class UbuntuCommands < DebianCommands
def running?(hosts, package)
stdout = ""
at(hosts, {in: :serial}) do |host|
cmd = sudo_exec!("service #{package} status")
stdout = cmd.stdout
end
stdout.match(/^#{package} is running$/)
end
end
end

View file

@ -9,6 +9,10 @@ module ServiceTester
@servers = []
@lookup = {}
end
def hosts
lookup.values.map { |val| val["host"] }
end
end
class << self
@ -24,22 +28,6 @@ module ServiceTester
ServiceTester.configuration.servers
end
def install(package, host=nil)
select_client.install(package, host)
end
def uninstall(package, host=nil)
select_client.uninstall(package, host)
end
def start_service(service, host=nil)
select_client.service_manager(service, "start", host)
end
def stop_service(service, host=nil)
select_client.service_manager(service, "stop", host)
end
def select_client
CommandsFactory.fetch(current_example.metadata[:platform])
end

View file

@ -4,22 +4,13 @@ require_relative '../helpers'
RSpec::Matchers.define :be_installed do
match do |actual|
select_client.installed?([@host], actual)
end
chain :on do |host|
@host = host
match do |subject|
subject.installed?(subject.hosts, subject.name)
end
end
RSpec::Matchers.define :be_removed do
match do |actual|
select_client.removed?([@host], actual)
end
chain :on do |host|
@host = host
match do |subject|
subject.removed?(subject.hosts, subject.name)
end
end

View file

@ -4,11 +4,7 @@ require_relative '../helpers'
RSpec::Matchers.define :be_running do
match do |actual|
select_client.running?([@host], actual)
end
chain :on do |host|
@host = host
match do |subject|
subject.running?(subject.hosts, subject.name)
end
end

4
qa/sys/suse/bootstrap.sh Normal file
View file

@ -0,0 +1,4 @@
#!/usr/bin/env bash
zypper --non-interactive list-updates
zypper --non-interactive --no-gpg-checks --quiet install --no-recommends java-1_8_0-openjdk-devel

View file

@ -35,7 +35,7 @@ module LogStash
# was not run successfully and will display the content of STDERR
def self.run!(cmd)
response = run(cmd)
unless response.success?
raise CommandError, "CMD: #{cmd} STDERR: #{response.stderr}"
end
@ -45,12 +45,22 @@ module LogStash
class VagrantHelpers
def self.bootstrap
CommandExecutor.run!("vagrant up")
def self.halt(machines="")
CommandExecutor.run!("vagrant halt #{machines.join(' ')}")
end
def self.destroy(machines="")
CommandExecutor.run!("vagrant destroy --force #{machines.join(' ')}")
end
def self.bootstrap(machines="")
CommandExecutor.run!("vagrant up #{machines.join(' ')}")
end
def self.fetch_config
CommandExecutor.run!("vagrant ssh-config")
cmd = CommandExecutor.run!("vagrant status")
machines = cmd.stdout.split("\n").select { |m| m.include?("running") }.map { |s| s.split(" ")[0] }
CommandExecutor.run!("vagrant ssh-config #{machines.join(' ')}")
end
def self.parse(lines)