lopata 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1da20f2c64537408a58e5880567aed444ec8d316
4
+ data.tar.gz: 2d8f0ccf72c30d3891dd0b0ce8eaba4654cc6635
5
+ SHA512:
6
+ metadata.gz: 37590ac64353a64346303e46ff53af169ac6c7064bc71794de18887d719cbe4a44baa82f8ac5e5d7e491f5e75b024ff3504607ee98787773dd8484d489c408b1
7
+ data.tar.gz: 2c32502a4f077ae9ca29886bd98c476991878d029f48f048309ecb9230b12b702fdc72006d44c93d39e860ad76a1ff0143dda781caf55d7db7eeed24777988c3
@@ -0,0 +1,2 @@
1
+ # Lopata - functional acceptance testing
2
+
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require 'bundler/setup' # TODO - remove after debugging
3
+ require_relative '../lib/lopata/runner'
4
+ Lopata::Runner.start ARGV
@@ -0,0 +1,2 @@
1
+ require 'lopata/id'
2
+ require 'lopata/config'
@@ -0,0 +1,43 @@
1
+ module Lopata
2
+ module Config
3
+ extend self
4
+
5
+ attr_accessor :build_number, :lopata_host, :only_roles, :role_descriptions, :after_as, :ops
6
+
7
+ def init(env)
8
+ require 'yaml'
9
+ @config = YAML::load(File.open("./config/environments/#{env}.yml")) || {}
10
+ init_db
11
+ @role_descriptions ||= {}
12
+ # init_includes
13
+ end
14
+
15
+ %w{url name readonly}.each do |opt|
16
+ define_method opt do
17
+ raise "RstConfig unititlalized, use RstConfig#init(env) to set environment" unless @config
18
+ @config[opt]
19
+ end
20
+ end
21
+
22
+ def init_db
23
+ ActiveRecord::Base.establish_connection(@config['db']) if @config['db']
24
+ end
25
+
26
+ def init_rspec
27
+ require 'lopata/rspec/dsl'
28
+ require 'lopata/rspec/role'
29
+ ::RSpec.configure do |c|
30
+ c.include Lopata::RSpec::DSL
31
+ c.include Lopata::RSpec::Role
32
+ end
33
+ end
34
+
35
+ def before_start(&block)
36
+ @before_start = block
37
+ end
38
+
39
+ def initialize_test
40
+ @before_start.call if @before_start
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,54 @@
1
+ module Lopata
2
+ module DownloadDir
3
+ RELATIVE_PATH = './tmp/target'
4
+
5
+ extend self
6
+
7
+ def path
8
+ @path ||= File.absolute_path(RELATIVE_PATH).gsub("/", '\\')
9
+ end
10
+
11
+ def empty!
12
+ FileUtils.rm Dir.glob("#{RELATIVE_PATH}/*")
13
+ end
14
+
15
+ def ensure_exist
16
+ FileUtils::mkdir_p RELATIVE_PATH unless Dir.exist?(RELATIVE_PATH)
17
+ end
18
+
19
+ def has_file?(file_name)
20
+ require 'timeout'
21
+ target_file = File.join(RELATIVE_PATH, file_name)
22
+ Timeout.timeout(10) do
23
+ sleep 0.1 until File.exist?(target_file)
24
+ true
25
+ end
26
+ rescue Timeout::Error
27
+ false
28
+ end
29
+
30
+ def init_capybara
31
+ profile = Selenium::WebDriver::Firefox::Profile.new
32
+ profile['browser.download.folderList'] = 2
33
+ profile['browser.download.manager.showWhenStarting'] = false
34
+ ensure_exist
35
+ profile['browser.download.dir'] = path
36
+ profile['browser.download.downloadDir'] = path
37
+ profile['browser.download.defaultFolder'] = path
38
+ profile['browser.helperApps.alwaysAsk.force'] = false
39
+ profile['browser.download.useDownloadDir'] = true
40
+ profile['browser.helperApps.neverAsk.saveToDisk'] =
41
+ "application/octet-stream, application/msword, application/pdf, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
42
+
43
+ Capybara.register_driver :selenium_with_download do |app|
44
+ Capybara::Selenium::Driver.new(
45
+ app,
46
+ {:browser => :firefox, :profile => profile}
47
+ )
48
+ end
49
+
50
+ Capybara.default_driver = :selenium_with_download
51
+ # Capybara.default_max_wait_time = 10
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,30 @@
1
+ module Lopata
2
+ module Generators
3
+ class App < Thor::Group
4
+ include Thor::Actions
5
+ argument :name
6
+
7
+ def self.source_root
8
+ File.join(File.dirname(__FILE__), 'templates')
9
+ end
10
+
11
+ def create_root_files
12
+ template 'Lopatafile', "#{name}/Lopatafile"
13
+ template 'Gemfile', "#{name}/Gemfile"
14
+ template '.rspec', "#{name}/.rspec"
15
+ template 'config/environments/qa.yml', "#{name}/config/environments/qa.yml"
16
+ template 'config/initializers/capybara.rb', "#{name}/config/initializers/capybara.rb"
17
+ end
18
+
19
+ def init_dirs
20
+ %w{models services pages}.each do |dir|
21
+ empty_directory "#{name}/app/#{dir}"
22
+ end
23
+
24
+ %w{spec config/initializers}.each do |dir|
25
+ empty_directory "#{name}/#{dir}"
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+ gem 'selenium-webdriver'
3
+ gem 'rspec', :require => 'spec'
4
+ gem 'rake'
5
+ gem 'activerecord', '~> 4.2.0'
6
+ gem 'capybara', '~> 2.2.1' # fix capybara version to avoid capybara-angular deprication varnings.
7
+ # gem 'capybara-angular'
8
+ gem 'thor'
9
+ # gem 'pg'
10
+ # gem 'factory_girl'
11
+ # gem 'lopata', path: 'vendor/lopata'
@@ -0,0 +1,21 @@
1
+ # coding: utf-8
2
+ Encoding.default_external = Encoding::UTF_8
3
+ Encoding.default_internal = Encoding::UTF_8
4
+
5
+ require 'rubygems'
6
+ require 'bundler/setup'
7
+ require 'active_support/all'
8
+ require 'capybara'
9
+ require 'capybara/angular'
10
+ require 'selenium/webdriver'
11
+ require 'fileutils'
12
+ require 'active_support'
13
+ require 'active_record'
14
+ require 'factory_girl'
15
+ require 'lopata'
16
+
17
+ relative_load_paths = %w[app/pages app/services app/models]
18
+ ActiveSupport::Dependencies.autoload_paths += relative_load_paths
19
+
20
+ Dir["./config/initializers/*.rb"].each { |f| require f }
21
+
@@ -0,0 +1,8 @@
1
+ url: http://yourapp.com
2
+ name: QA
3
+ # db:
4
+ # adapter: postgresql
5
+ # host: localhost
6
+ # username: username
7
+ # password: password
8
+ # database: database
@@ -0,0 +1 @@
1
+ Capybara.default_driver = :selenium if defined? Capybara
@@ -0,0 +1,21 @@
1
+ module Lopata
2
+ module Id
3
+ extend self
4
+
5
+ def next(prefix = nil)
6
+ id = "%d_%d" % [timestamp, seq_num]
7
+ id = "%s_%s" % [prefix, id] if prefix
8
+ id
9
+ end
10
+
11
+ def timestamp
12
+ @timestamp ||= Time.now.strftime("%Y%m%d%H%M%S")
13
+ end
14
+
15
+ def seq_num
16
+ @seq_num ||= 0
17
+ @seq_num += 1
18
+ @seq_num
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,39 @@
1
+ module Lopata
2
+ module RSpec
3
+ module DSL
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def action *contexts, &block
10
+ contexts.each do |context|
11
+ if context.is_a?(Proc)
12
+ action(&context)
13
+ else
14
+ include_context context
15
+ end
16
+ end
17
+ before(:all, &block) if block_given?
18
+ end
19
+
20
+ def setup *contexts, &block
21
+ root_setup = false
22
+ unless @doing_setup
23
+ root_setup = true
24
+ @doing_setup = true
25
+ end
26
+ action *contexts, &block
27
+ if root_setup
28
+ # action Config.after_setup if Config.after_setup
29
+ @doing_setup = false
30
+ end
31
+ end
32
+
33
+ def teardown &block
34
+ after(:all, &block) if block_given?
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,137 @@
1
+ require 'rspec/core/formatters/base_formatter'
2
+ require 'httparty'
3
+ require 'json'
4
+ require 'lopata/config'
5
+
6
+ module Lopata
7
+ module RSpec
8
+ class Formatter < ::RSpec::Core::Formatters::BaseFormatter
9
+ ::RSpec::Core::Formatters.register self, :start, :example_passed, :example_pending, :example_failed
10
+
11
+ def start(notification)
12
+ raise "Build number is not initailzed in Lopata::Config" unless Lopata::Config.build_number
13
+ @client = Lopata::Client.new(Lopata::Config.build_number)
14
+ @client.start(notification.count)
15
+ end
16
+
17
+ def example_passed(notification)
18
+ @client.add_attempt(notification.example, Lopata::PASSED)
19
+ end
20
+
21
+ def example_failed(notification)
22
+ example = notification.example
23
+ @client.add_attempt(example, Lopata::FAILED, error_message_for(example), backtrace_for(notification))
24
+ end
25
+
26
+ def example_pending(notification)
27
+ example = notification.example
28
+ @client.add_attempt(example, Lopata::PENDING, example.execution_result.pending_message)
29
+ end
30
+
31
+ private
32
+
33
+ def error_message_for(example)
34
+ exception = example.execution_result.exception
35
+ msg = ''
36
+ msg << "#{exception.class.name}: " unless exception.class.name =~ /RSpec/
37
+ msg << "#{exception.message.to_s}" if exception.message
38
+ msg.blank? ? 'Empty message' : msg
39
+ end
40
+
41
+ def backtrace_for(notification)
42
+ example = notification.example
43
+ exception = example.execution_result.exception
44
+ msg = notification.message_lines.map(&:strip).join("\n")
45
+ msg << "\n"
46
+ if shared_group = find_shared_group(example)
47
+ msg << "# Shared Example Group: \"#{shared_group.metadata[:shared_group_name]}\" called from "
48
+ msg << "#{backtrace_line(shared_group.metadata[:example_group][:location])}\n"
49
+ end
50
+ msg
51
+ end
52
+
53
+ def find_shared_group(example)
54
+ group_and_parent_groups(example).find {|group| group.metadata[:shared_group_name]}
55
+ end
56
+
57
+ def group_and_parent_groups(example)
58
+ example.example_group.parent_groups + [example.example_group]
59
+ end
60
+ end
61
+ end
62
+
63
+ PASSED = 0
64
+ FAILED = 1
65
+ PENDING = 2
66
+
67
+ class Client
68
+ include HTTParty
69
+ base_uri Lopata::Config.lopata_host
70
+
71
+ attr_accessor :build_number
72
+
73
+ def initialize(build_number)
74
+ @build_number = build_number
75
+ end
76
+
77
+ def start(count)
78
+ @launch_id = JSON.parse(post("/builds/#{build_number}/launches.json", body: {total: count}).body)['id']
79
+ end
80
+
81
+ def add_attempt(example, status, msg = nil, backtrace = nil)
82
+ test = test_id(example)
83
+ request = { status: status}
84
+ request[:message] = msg if msg
85
+ request[:backtrace] = backtrace if backtrace
86
+ post("/tests/#{test}/attempts.json", body: request)
87
+ inc_finished
88
+ end
89
+
90
+ def test_id(example)
91
+ request = {
92
+ find_or_create: {
93
+ title: example.full_description,
94
+ scenario: example.metadata[:example_group][:full_description],
95
+ build_number: build_number
96
+ }
97
+ }
98
+ response = post("/tests.json", body: request)
99
+ JSON.parse(response.body)["id"]
100
+ end
101
+
102
+ def to_rerun
103
+ get_json("/builds/#{build_number}/suspects.json")
104
+ end
105
+
106
+ def to_full_rescan
107
+ to_rerun + get_json("/builds/#{build_number}/failures.json")
108
+ end
109
+
110
+ private
111
+
112
+ def get_json(url)
113
+ JSON.parse(self.class.get(url).body)
114
+ end
115
+
116
+ def post(*args)
117
+ self.class.post(*args)
118
+ end
119
+
120
+ def patch(*args)
121
+ self.class.patch(*args)
122
+ end
123
+
124
+ def inc_finished
125
+ @finished ||= 0
126
+ @finished += 1
127
+ response = patch("/builds/#{build_number}/launches/#{@launch_id}",
128
+ body: { finished: @finished }.to_json,
129
+ headers: { 'Content-Type' => 'application/json', 'Accept' => 'application/json' })
130
+ if response.code == 404
131
+ puts 'Launch has been cancelled. Exit.'
132
+ exit!
133
+ end
134
+ end
135
+ end
136
+ end
137
+
@@ -0,0 +1,75 @@
1
+ module Lopata::RSpec::Role
2
+ def self.included(base)
3
+ base.extend(ClassMethods)
4
+ end
5
+
6
+ # Filter names
7
+ def self.filter_roles *names
8
+ allowed = Lopata::Config.only_roles
9
+ selected = names.flatten.select { |n| allowed.blank? || allowed.member?(n) }
10
+ # ENV['quick'] ? [selected.first] : selected
11
+ selected
12
+ end
13
+
14
+ # http://jorgemanrubia.net/2010/01/16/using-macros-to-create-custom-example-groups-in-rspec/
15
+ module ClassMethods
16
+ def as *names, &block
17
+ return if current_role && !Lopata::RSpec::Role.filter_roles(*names).include?(current_role)
18
+ if current_role
19
+ self.class_eval(&block)
20
+ else
21
+ Lopata::RSpec::Role.filter_roles(*names).each do |name|
22
+ example_group_class = describe role_description(name), :current_role => name do
23
+ instance_exec &Lopata::Config.after_as if Lopata::Config.after_as
24
+ define_method :current_role do
25
+ name
26
+ end
27
+ end
28
+ example_group_class.class_eval(&block)
29
+ end
30
+ end
31
+ end
32
+
33
+ def except(*names, &block)
34
+ raise "'expecpt' block must be neseted for 'as' block" unless current_role
35
+ return if names.include? current_role
36
+ self.class_eval(&block)
37
+ end
38
+
39
+ def current_role
40
+ metadata[:current_role]
41
+ end
42
+
43
+ # To be redefined in impelemntations so RSpec descriptions to be more verbal
44
+ def role_description(name)
45
+ Lopata::Config.role_descriptions[name] || name
46
+ end
47
+
48
+ def scenario(*args, &block)
49
+ raise "scenario required a name in first argument" unless args.first.is_a? String
50
+ example_group_class = describe(*args)
51
+ example_group_class.nested_with_as(*args, &block)
52
+ end
53
+
54
+ def nested_with_as(*args, &block)
55
+ if (args.last.is_a?(Hash) && args.last[:as])
56
+ roles = args.last[:as]
57
+ roles = [roles] unless roles.is_a?(Array)
58
+ class_eval { as(*roles, &block) }
59
+ else
60
+ class_eval(&block)
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ module Lopata
67
+ # Adds the #scenario method to the top-level namespace.
68
+ def self.scenario(*args, &block)
69
+ raise "scenario required a name in first argument" unless args.first.is_a? String
70
+ example_group_class = RSpec.describe(*args)
71
+ example_group_class.nested_with_as(*args, &block)
72
+ # example_group_class.register
73
+ end
74
+ end
75
+
@@ -0,0 +1,7 @@
1
+ module Lopata
2
+ module RSpec
3
+ module Version
4
+ STRING = '0.0.2'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,40 @@
1
+ require 'thor'
2
+ require_relative 'generators/app'
3
+ require_relative 'config'
4
+
5
+ module Lopata
6
+ class Runner < Thor
7
+ desc 'test', 'Run tests'
8
+ option :env, default: :qa, aliases: 'e'
9
+ option :"no-log", type: :boolean, aliases: 'n'
10
+ option :focus, type: :boolean, aliases: 'f'
11
+ option :rerun, type: :boolean, aliases: 'r'
12
+ option :users, type: :array, aliases: 'u'
13
+ option :build, aliases: 'b'
14
+ def test
15
+ require 'rspec'
16
+
17
+ Dir["./spec/support/**/*.rb"].sort.each { |f| require f}
18
+ ENV['HOME'] = File.absolute_path('.') # disable warning on rspec loading on windows
19
+ Lopata::Config.ops = {
20
+ focus: options[:focus],
21
+ rerun: options[:rerun],
22
+ users: options[:users],
23
+ build: options[:build],
24
+ env: options[:env],
25
+ }
26
+ Lopata::Config.init(options[:env])
27
+ Lopata::Config.initialize_test
28
+
29
+ ::RSpec::Core::Runner.run ['spec']
30
+ end
31
+
32
+ default_task :test
33
+
34
+ register Generators::App, :new, 'lopata new project-name', 'Init new lopata projects'
35
+ end
36
+ end
37
+
38
+ raise 'No Lopatafile found in running dir' unless File.exists?('./Lopatafile')
39
+ eval File.binread('./Lopatafile')
40
+
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lopata
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Alexey Volochnev
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-03-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httparty
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Functional acceptance tesging with rspec
42
+ email: alexey.volochnev@gmail.com
43
+ executables:
44
+ - lopata
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - README.md
49
+ - exe/lopata
50
+ - lib/lopata.rb
51
+ - lib/lopata/config.rb
52
+ - lib/lopata/download_dir.rb
53
+ - lib/lopata/generators/app.rb
54
+ - lib/lopata/generators/templates/.rspec
55
+ - lib/lopata/generators/templates/Gemfile
56
+ - lib/lopata/generators/templates/Lopatafile
57
+ - lib/lopata/generators/templates/config/environments/qa.yml
58
+ - lib/lopata/generators/templates/config/initializers/capybara.rb
59
+ - lib/lopata/id.rb
60
+ - lib/lopata/rspec/dsl.rb
61
+ - lib/lopata/rspec/formatter.rb
62
+ - lib/lopata/rspec/role.rb
63
+ - lib/lopata/rspec/version.rb
64
+ - lib/lopata/runner.rb
65
+ homepage:
66
+ licenses:
67
+ - MIT
68
+ metadata: {}
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: 2.1.0
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ requirements: []
84
+ rubyforge_project:
85
+ rubygems_version: 2.2.5
86
+ signing_key:
87
+ specification_version: 4
88
+ summary: lopata-0.0.2
89
+ test_files: []