kraken-mobile 1.0.1 → 1.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +251 -77
  3. data/bin/kraken-mobile +64 -67
  4. data/bin/kraken_mobile_calabash_android.rb +39 -0
  5. data/bin/kraken_mobile_helpers.rb +107 -0
  6. data/bin/kraken_mobile_setup.rb +138 -0
  7. data/calabash-android-features-skeleton/step_definitions/mobile_steps.rb +1 -0
  8. data/calabash-android-features-skeleton/support/app_installation_hooks.rb +2 -0
  9. data/calabash-android-features-skeleton/support/app_life_cycle_hooks.rb +3 -4
  10. data/calabash-android-features-skeleton/support/env.rb +1 -1
  11. data/calabash-android-features-skeleton/web/step_definitions/web_steps.rb +3 -0
  12. data/calabash-android-features-skeleton/web/support/app_life_cycle_hooks.rb +15 -0
  13. data/lib/kraken-mobile/device_process.rb +130 -0
  14. data/lib/kraken-mobile/helpers/devices_helper/adb_helper.rb +100 -105
  15. data/lib/kraken-mobile/helpers/kraken_faker.rb +108 -0
  16. data/lib/kraken-mobile/helpers/reporter.rb +3 -0
  17. data/lib/kraken-mobile/hooks/mobile_kraken_hooks.rb +15 -0
  18. data/lib/kraken-mobile/hooks/mobile_operations.rb +36 -0
  19. data/lib/kraken-mobile/hooks/web_operations.rb +33 -0
  20. data/lib/kraken-mobile/mobile/adb.rb +66 -0
  21. data/lib/kraken-mobile/mobile/android_commands.rb +43 -0
  22. data/lib/kraken-mobile/mobile/mobile_process.rb +101 -0
  23. data/lib/kraken-mobile/models/android_device.rb +121 -0
  24. data/lib/kraken-mobile/models/device.rb +113 -31
  25. data/lib/kraken-mobile/models/feature_file.rb +135 -0
  26. data/lib/kraken-mobile/models/feature_scenario.rb +24 -0
  27. data/lib/kraken-mobile/models/web_device.rb +89 -0
  28. data/lib/kraken-mobile/monkeys/mobile/android_monkey.rb +30 -0
  29. data/lib/kraken-mobile/monkeys/mobile/kraken_android_monkey.rb +54 -0
  30. data/lib/kraken-mobile/monkeys/web/web_monkey.rb +63 -0
  31. data/lib/kraken-mobile/runners/calabash/android/monkey_helper.rb +2 -2
  32. data/lib/kraken-mobile/runners/calabash/android/steps/communication_steps.rb +18 -2
  33. data/lib/kraken-mobile/runners/calabash/monkey/monkey_runner.rb +2 -2
  34. data/lib/kraken-mobile/steps/general_steps.rb +83 -0
  35. data/lib/kraken-mobile/steps/mobile/kraken_steps.rb +72 -0
  36. data/lib/kraken-mobile/steps/web/kraken_steps.rb +91 -0
  37. data/lib/kraken-mobile/test_scenario.rb +227 -0
  38. data/lib/kraken-mobile/utils/feature_reader.rb +17 -0
  39. data/lib/kraken-mobile/utils/k.rb +68 -0
  40. data/lib/kraken-mobile/utils/mobile_cucumber.rb +2 -0
  41. data/lib/kraken-mobile/utils/reporter.rb +500 -0
  42. data/lib/kraken-mobile/version.rb +2 -2
  43. data/lib/kraken-mobile/web/web_process.rb +41 -0
  44. data/lib/kraken_mobile.rb +81 -0
  45. data/reporter/assets/css/scenario_index.css +20 -0
  46. data/reporter/assets/images/krakenThumbnail.jpg +0 -0
  47. data/reporter/assets/js/sankey.js +56 -24
  48. data/reporter/feature_report.html.erb +5 -1
  49. data/reporter/index.html.erb +15 -8
  50. data/reporter/scenario_report.html.erb +73 -31
  51. metadata +95 -14
  52. data/bin/kraken-mobile-calabash-android.rb +0 -85
  53. data/bin/kraken-mobile-generate.rb +0 -19
  54. data/bin/kraken-mobile-helpers.rb +0 -48
  55. data/bin/kraken-mobile-setup.rb +0 -50
  56. data/calabash-android-features-skeleton/step_definitions/kraken_steps.rb +0 -1
  57. data/lib/kraken-mobile.rb +0 -29
@@ -0,0 +1,135 @@
1
+ require 'gherkin/parser'
2
+ require 'gherkin/pickles/compiler'
3
+ require 'kraken-mobile/models/feature_scenario'
4
+
5
+ class FeatureFile
6
+ #-------------------------------
7
+ # Fields
8
+ #-------------------------------
9
+ attr_accessor :file_path
10
+ attr_accessor :scenarios
11
+
12
+ #-------------------------------
13
+ # Constructos
14
+ #-------------------------------
15
+ def initialize(file_path:)
16
+ @file_path = file_path
17
+ @scenarios = []
18
+
19
+ read_content
20
+ end
21
+
22
+ #-------------------------------
23
+ # Helpers
24
+ #-------------------------------
25
+ def user_tags
26
+ all_tags = @scenarios.map(&:tags).flatten.uniq
27
+ all_tags.select { |tag| tag.start_with?('@user') }
28
+ end
29
+
30
+ def system_tags
31
+ @scenarios.map do |scenario|
32
+ tags = scenario.tags
33
+ system_tag = tags.select do |tag|
34
+ tag.start_with?('@web') || tag.start_with?('@mobile')
35
+ end.first
36
+ system_tag || '@mobile'
37
+ end
38
+ end
39
+
40
+ def number_of_required_mobile_devices
41
+ system_tags.select { |tag| tag == '@mobile' }.count
42
+ end
43
+
44
+ def number_of_required_web_devices
45
+ system_tags.select { |tag| tag == '@web' }.count
46
+ end
47
+
48
+ def number_of_required_devices
49
+ user_tags.count
50
+ end
51
+
52
+ def required_devices
53
+ users = user_tags
54
+ systems = system_tags
55
+
56
+ users.map do |user|
57
+ {
58
+ user_id: user.delete_prefix('@user'),
59
+ system_type: systems.shift || '@mobile'
60
+ }
61
+ end
62
+ end
63
+
64
+ def sorted_required_devices
65
+ required_devices.sort_by do |device|
66
+ device[:user_id].to_i
67
+ end
68
+ end
69
+
70
+ def tags_for_user_id(user_id)
71
+ user_tag = "@user#{user_id}"
72
+ user_scenario = @scenarios.select do |scenario|
73
+ scenario.tags.include?(user_tag)
74
+ end.first
75
+ return [] if user_scenario.nil? || user_scenario.tags.nil?
76
+
77
+ user_scenario.tags.reject { |tag| tag == user_tag }
78
+ end
79
+
80
+ def right_syntax?
81
+ all_scenarios_have_a_user_tag? &&
82
+ only_one_user_tag_for_each_scenario? &&
83
+ !duplicate_tags_for_a_user?
84
+ end
85
+
86
+ def duplicate_tags_for_a_user?
87
+ taken_user_tags = {}
88
+ scenarios.each do |scenario|
89
+ user_tag = scenario.tags.select do |tag|
90
+ tag.start_with?('@user')
91
+ end.first
92
+ return true unless taken_user_tags[user_tag].nil?
93
+
94
+ taken_user_tags[user_tag] = user_tag
95
+ end
96
+ false
97
+ end
98
+
99
+ def only_one_user_tag_for_each_scenario?
100
+ scenarios.each do |scenario|
101
+ user_tags = scenario.tags.select do |tag|
102
+ tag.start_with?('@user')
103
+ end
104
+ return false if user_tags.count != 1
105
+ end
106
+ true
107
+ end
108
+
109
+ def all_scenarios_have_a_user_tag?
110
+ scenarios.each do |scenario|
111
+ user_tag = scenario.tags.select do |tag|
112
+ tag.start_with?('@user')
113
+ end.first
114
+ return false if user_tag.nil?
115
+ end
116
+ true
117
+ end
118
+
119
+ private
120
+
121
+ def read_content
122
+ parser = Gherkin::Parser.new
123
+ file = File.open(file_path)
124
+ file_content = file.read
125
+ file.close
126
+ gherkin_document = parser.parse(file_content)
127
+ pickles = Gherkin::Pickles::Compiler.new.compile(gherkin_document)
128
+ pickles.each do |scenario|
129
+ scenarios << FeatureScenario.new(
130
+ name: scenario[:name],
131
+ tags: scenario[:tags]
132
+ )
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,24 @@
1
+ class FeatureScenario
2
+ #-------------------------------
3
+ # Fields
4
+ #-------------------------------
5
+ attr_accessor :name
6
+ attr_accessor :tags
7
+
8
+ #-------------------------------
9
+ # Constructos
10
+ #-------------------------------
11
+ def initialize(name:, tags:)
12
+ @name = name
13
+ @tags = format_tags(tags) || []
14
+ end
15
+
16
+ private
17
+
18
+ #-------------------------------
19
+ # Helpers
20
+ #-------------------------------
21
+ def format_tags(tags)
22
+ tags.map { |tag| tag[:name] }
23
+ end
24
+ end
@@ -0,0 +1,89 @@
1
+ require 'kraken-mobile/models/device'
2
+
3
+ class WebDevice < Device
4
+ #-------------------------------
5
+ # Signaling
6
+ #-------------------------------
7
+ def create_inbox
8
+ file = File.open(inbox_file_path, 'w')
9
+ file.close
10
+ end
11
+
12
+ def delete_inbox
13
+ return unless File.exist? inbox_file_path
14
+
15
+ File.delete(inbox_file_path)
16
+ end
17
+
18
+ def write_signal(signal)
19
+ File.open(inbox_file_path, 'a') do |file|
20
+ file.puts(signal)
21
+ end
22
+ end
23
+
24
+ def read_signal(signal, timeout = K::DEFAULT_TIMEOUT_SECONDS)
25
+ Timeout.timeout(timeout, RuntimeError) do
26
+ sleep(1) until inbox_last_signal == signal
27
+ end
28
+ end
29
+
30
+ #-------------------------------
31
+ # More interface methods
32
+ #-------------------------------
33
+ def connected?
34
+ true
35
+ end
36
+
37
+ def orientation
38
+ K::WEB_PORTRAIT
39
+ end
40
+
41
+ def screen_size
42
+ height = 0
43
+ width = 0
44
+
45
+ [height, width]
46
+ end
47
+
48
+ def sdk_version
49
+ 1.0 # Default
50
+ end
51
+
52
+ def type
53
+ K::WEB_DEVICE
54
+ end
55
+
56
+ #-------------------------------
57
+ # Random testing
58
+ #-------------------------------
59
+ def run_monkey_with_number_of_events(number_of_events)
60
+ number_of_events # TODO, implement
61
+ end
62
+
63
+ def run_kraken_monkey_with_number_of_events(number_of_events)
64
+ number_of_events # TODO, implement
65
+ end
66
+
67
+ #-------------------------------
68
+ # Helpers
69
+ #-------------------------------
70
+ def self.factory_create
71
+ WebDevice.new(
72
+ id: SecureRandom.hex(10),
73
+ model: 'Web'
74
+ )
75
+ end
76
+
77
+ private
78
+
79
+ def inbox_file_path
80
+ ".#{@id}_#{K::INBOX_FILE_NAME}"
81
+ end
82
+
83
+ def inbox_last_signal
84
+ file = File.open(inbox_file_path)
85
+ lines = file.to_a
86
+ file.close
87
+ lines.last&.strip
88
+ end
89
+ end
@@ -0,0 +1,30 @@
1
+ require 'calabash-android/environment_helpers.rb'
2
+ require 'calabash-android/monkey_helpers'
3
+ require 'calabash-android/operations'
4
+
5
+ module AndroidMonkey
6
+ include Calabash::Android::Operations
7
+ include Calabash::Android::MonkeyHelpers
8
+
9
+ def execute_monkey(number_of_events)
10
+ height, width = screen_size
11
+ start_monkey
12
+
13
+ number_of_events.times do |_i|
14
+ monkey_touch(
15
+ K::CALABASH_MONKEY_ACTIONS.sample,
16
+ rand(5..(width - 5)),
17
+ rand(5..(height - 5))
18
+ )
19
+ end
20
+
21
+ kill_existing_monkey_processes
22
+ end
23
+
24
+ private
25
+
26
+ # Override calabash super adb_command method
27
+ def adb_command
28
+ calabash_default_device.adb_command
29
+ end
30
+ end
@@ -0,0 +1,54 @@
1
+ module KrakenAndroidMonkey
2
+ def execute_kraken_monkey(number_of_events)
3
+ number_of_events.times do |_i|
4
+ execute_random_action
5
+ end
6
+ end
7
+
8
+ def execute_random_action
9
+ Timeout.timeout(K::MONKEY_DEFAULT_TIMEOUT, RuntimeError) do
10
+ begin
11
+ arr = [
12
+ method(:random_click), method(:insert_random_text)
13
+ ]
14
+ arr.sample.call
15
+ rescue StandardError => _e
16
+ puts 'ERROR: Kraken monkey couldn\'t perfom action'
17
+ end
18
+ end
19
+ end
20
+
21
+ # Actions
22
+ private
23
+
24
+ def random_click
25
+ elements = query('*')
26
+ return if elements.nil?
27
+ return if elements.none?
28
+
29
+ element = elements.sample
30
+ return if element['rect'].nil?
31
+
32
+ x = element['rect']['x']
33
+ y = element['rect']['y']
34
+ perform_action('touch_coordinate', x, y)
35
+ end
36
+
37
+ def insert_random_text
38
+ inputs = query('android.support.v7.widget.AppCompatEditText')
39
+ return if inputs.nil?
40
+ return if inputs.none?
41
+
42
+ input = inputs.sample
43
+ return if input['rect'].nil?
44
+
45
+ x = input['rect']['x']
46
+ y = input['rect']['y']
47
+ perform_action('touch_coordinate', x, y)
48
+ enter_text SecureRandom.hex
49
+ end
50
+
51
+ def input_texts
52
+ query('android.support.v7.widget.AppCompatEditText')
53
+ end
54
+ end
@@ -0,0 +1,63 @@
1
+ require 'selenium-webdriver'
2
+ require 'faker'
3
+
4
+ class WebMonkey
5
+ attr_accessor :driver
6
+ attr_accessor :wait
7
+ DEFAULT_WAIT_TIMEOUT = 0.5
8
+
9
+ def initialize(driver:)
10
+ self.driver = driver
11
+ self.wait = Selenium::WebDriver::Wait.new(timeout: DEFAULT_WAIT_TIMEOUT)
12
+ end
13
+
14
+ # Helpers
15
+ def execute_kraken_monkey(number_of_events)
16
+ number_of_events.times do |_i|
17
+ execute_random_action
18
+ end
19
+ end
20
+
21
+ def execute_random_action
22
+ arr = [
23
+ method(:random_click), method(:insert_random_text)
24
+ ]
25
+ arr.sample.call
26
+ rescue StandardError => _e
27
+ nil
28
+ end
29
+
30
+ def random_click
31
+ element = @wait.until { driver.find_elements(:xpath, '//*').sample }
32
+ highlight_element(element)
33
+ element.click
34
+ remove_element_highlight(element)
35
+ end
36
+
37
+ def insert_random_text
38
+ element = @wait.until { driver.find_elements(:xpath, '//input').sample }
39
+ highlight_element(element)
40
+ element.click
41
+ text = [Faker::Lorem.word, Faker::Lorem.sentence].sample
42
+ element.send_keys(text)
43
+ remove_element_highlight(element)
44
+ end
45
+
46
+ private
47
+
48
+ def highlight_element(element)
49
+ @driver.execute_script(
50
+ "arguments[0].setAttribute('style', arguments[1]);",
51
+ element,
52
+ 'color: red; border: 2px solid red'
53
+ )
54
+ end
55
+
56
+ def remove_element_highlight(element)
57
+ @driver.execute_script(
58
+ "arguments[0].setAttribute('style', arguments[1]);",
59
+ element,
60
+ ''
61
+ )
62
+ end
63
+ end
@@ -5,8 +5,8 @@ module KrakenMobile
5
5
  module CalabashAndroid
6
6
  module MonkeyHelper
7
7
 
8
- # Runs inteligent monkey
9
- def run_intelligent_monkey channel, number_of_events
8
+ # Runs kraken monkey
9
+ def run_kraken_monkey channel, number_of_events
10
10
  device_id = channel_to_device_id channel
11
11
  logger = open("./#{device_id}.txt", 'w')
12
12
  number_of_events.times do |i|
@@ -9,6 +9,7 @@ ParameterType(
9
9
  s.slice!(">")
10
10
  file = open(ENV["PROPERTIES_PATH"])
11
11
  content = file.read
12
+ file.close
12
13
  properties = JSON.parse(content)
13
14
  raise "Property <#{s}> not found for #{channel}" if !properties[channel] || !properties[channel][s]
14
15
  return properties[channel][s]
@@ -18,6 +19,21 @@ ParameterType(
18
19
  }
19
20
  )
20
21
 
22
+ ParameterType(
23
+ name: 'property',
24
+ regexp: /[^\"]*/,
25
+ type: String,
26
+ transformer: ->(s) {
27
+ channel = @scenario_tags.grep(/@user/).first
28
+ if ENV["PROPERTIES_PATH"] && channel && s.start_with?("<") && s.end_with?(">")
29
+ s.slice!('$')
30
+ return properties[channel][s]
31
+ else
32
+ return s
33
+ end
34
+ }
35
+ )
36
+
21
37
  Then /^I wait for a signal containing "([^\"]*)"$/ do |string|
22
38
  channel = @scenario_tags.grep(/@user/).first
23
39
  readSignal(channel, string, KrakenMobile::Constants::DEFAULT_TIMEOUT)
@@ -46,9 +62,9 @@ Then /^I start a monkey with (\d+) events$/ do |int|
46
62
  run_monkey channel, int
47
63
  end
48
64
 
49
- Then /^I start a intelligent monkey with (\d+) events$/ do |int|
65
+ Then /^I start kraken monkey with (\d+) events$/ do |int|
50
66
  channel = @scenario_tags.grep(/@user/).first
51
- run_intelligent_monkey channel, int
67
+ run_kraken_monkey channel, int
52
68
  end
53
69
 
54
70
  Then /^I start a monkey with (\d+) events from height (\d+)% to (\d+)% and width (\d+)% to (\d+)%$/ do |int, from_x, to_x, from_y, to_y|