kraken-mobile 1.0.2 → 1.0.9

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.
Files changed (54) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +251 -75
  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 +109 -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/images/krakenThumbnail.jpg +0 -0
  46. data/reporter/feature_report.html.erb +5 -1
  47. data/reporter/index.html.erb +13 -7
  48. metadata +94 -13
  49. data/bin/kraken-mobile-calabash-android.rb +0 -85
  50. data/bin/kraken-mobile-generate.rb +0 -19
  51. data/bin/kraken-mobile-helpers.rb +0 -48
  52. data/bin/kraken-mobile-setup.rb +0 -50
  53. data/calabash-android-features-skeleton/step_definitions/kraken_steps.rb +0 -1
  54. 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|