stf-client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 65ca8ca05799cb4e254f7b962a362756427e37c5
4
+ data.tar.gz: 577b8bfaf8a406e993deca460e35f51e19878aba
5
+ SHA512:
6
+ metadata.gz: 33f66f05b6bf4388cf9e8761df25efccf7db732a3fd35efee84c18ad59e7570e5862d4489253cad930685a497ffe004ca9c155165f3056d38a5cd844c1e1b801
7
+ data.tar.gz: 188a7c5081a5cf27756b72d0888290572aecda5f77de7d59b7e677c0c3d07f609134e29ddf0928cd3ac67b35d506f58996212814fd9f3b0a62dea3779d07924a
data/.gitignore ADDED
@@ -0,0 +1,98 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ ### JetBrains template
11
+ # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
12
+ # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
13
+
14
+ # User-specific stuff:
15
+ .idea/workspace.xml
16
+ .idea/tasks.xml
17
+ .idea/dictionaries
18
+ .idea/vcs.xml
19
+ .idea/jsLibraryMappings.xml
20
+
21
+ # Sensitive or high-churn files:
22
+ .idea/dataSources.ids
23
+ .idea/dataSources.xml
24
+ .idea/dataSources.local.xml
25
+ .idea/sqlDataSources.xml
26
+ .idea/dynamic.xml
27
+ .idea/uiDesigner.xml
28
+
29
+ # Gradle:
30
+ .idea/gradle.xml
31
+ .idea/libraries
32
+
33
+ # Mongo Explorer plugin:
34
+ .idea/mongoSettings.xml
35
+
36
+ ## File-based project format:
37
+ *.iws
38
+
39
+ ## Plugin-specific files:
40
+
41
+ # IntelliJ
42
+ /out/
43
+
44
+ # mpeltonen/sbt-idea plugin
45
+ .idea_modules/
46
+
47
+ # JIRA plugin
48
+ atlassian-ide-plugin.xml
49
+
50
+ # Crashlytics plugin (for Android Studio and IntelliJ)
51
+ com_crashlytics_export_strings.xml
52
+ crashlytics.properties
53
+ crashlytics-build.properties
54
+ fabric.properties
55
+ ### Ruby template
56
+ *.gem
57
+ *.rbc
58
+ /.config
59
+ /InstalledFiles
60
+ /spec/examples.txt
61
+ /test/tmp/
62
+ /test/version_tmp/
63
+
64
+ # Used by dotenv library to load environment variables.
65
+ # .env
66
+
67
+ ## Specific to RubyMotion:
68
+ .dat*
69
+ .repl_history
70
+ build/
71
+ *.bridgesupport
72
+ build-iPhoneOS/
73
+ build-iPhoneSimulator/
74
+
75
+ ## Specific to RubyMotion (use of CocoaPods):
76
+ #
77
+ # We recommend against adding the Pods directory to your .gitignore. However
78
+ # you should judge for yourself, the pros and cons are mentioned at:
79
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
80
+ #
81
+ # vendor/Pods/
82
+
83
+ ## Documentation cache and generated files:
84
+ /.yardoc/
85
+ /rdoc/
86
+
87
+ ## Environment normalization:
88
+ /vendor/bundle
89
+ /lib/bundler/man/
90
+
91
+ # for a library or gem, you might want to ignore these files since the code is
92
+ # intended to run in multiple environments; otherwise, check them in:
93
+ # Gemfile.lock
94
+ # .ruby-version
95
+ # .ruby-gemset
96
+
97
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
98
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'ADB'
4
+ gem 'gli'
5
+
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Anton Malinskiy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,55 @@
1
+ # Stf::Client
2
+
3
+ Automation client for connecting to [OpenSTF](https://github.com/openstf/stf) devices.
4
+
5
+ Designed with the following scenario in mind:
6
+
7
+ 1. Connect to remote devices
8
+ 2. Do something with the device via adb (Instrumentation Test, adb install, etc)
9
+ 3. Disconnect from device
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ ```ruby
16
+ gem 'stf-client'
17
+ ```
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install stf-client
26
+
27
+ ## Usage
28
+
29
+ ```
30
+ NAME
31
+ stf-client - Smartphone Test Lab client
32
+
33
+ SYNOPSIS
34
+ stf-client [global options] command [command options] [arguments...]
35
+
36
+ GLOBAL OPTIONS
37
+ --help - Show this message
38
+ -t, --token=arg - Authorization token (default: none)
39
+ -u, --url=arg - URL to STF (default: none)
40
+ -v, --[no-]verbose - Be verbose
41
+
42
+ COMMANDS
43
+ clean - Frees all devices that are assigned to current user in STF. Doesn't modify local adb
44
+ connect - Search for a device available in STF and attach it to local adb server
45
+ disconnect - Disconnect device(s) from local adb server and remove device(s) from user devices in STF
46
+ help - Shows a list of commands or help for one command
47
+ ```
48
+
49
+ ## Contributing
50
+
51
+ Bug reports and pull requests are welcome on GitHub at https://github.com/Malinskiy/stf-client.
52
+
53
+ ## License
54
+
55
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'bundler/gem_tasks'
2
+ begin
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:spec)
5
+ rescue LoadError
6
+ end
7
+
8
+ task :default => :spec
9
+ task :test => :spec
data/bin/setup ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
data/bin/stf-client ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'stf'
data/lib/stf/client.rb ADDED
@@ -0,0 +1,75 @@
1
+ require 'net/http'
2
+ require 'json'
3
+ require 'ostruct'
4
+
5
+ require 'stf/version'
6
+ require 'stf/log/log'
7
+ require 'stf/errors'
8
+
9
+ module Stf
10
+ class Client
11
+ include Log
12
+
13
+ def initialize(base_url, token)
14
+ @base_url = base_url
15
+ @token = token
16
+ end
17
+
18
+ def get_devices
19
+ response = execute '/api/v1/devices', Net::HTTP::Get
20
+ return response.devices
21
+ end
22
+
23
+ def get_device(serial)
24
+ response = execute "/api/v1/devices/#{serial}", Net::HTTP::Get
25
+ return response.device
26
+ end
27
+
28
+ def get_user
29
+ response = execute '/api/v1/user', Net::HTTP::Get
30
+ return response.user
31
+ end
32
+
33
+ def get_user_devices
34
+ response = execute '/api/v1/user/devices', Net::HTTP::Get
35
+ return response.devices
36
+ end
37
+
38
+ def add_device(serial)
39
+ response = execute '/api/v1/user/devices', Net::HTTP::Post, {serial: serial}.to_json
40
+ return response.success
41
+ end
42
+
43
+ def remove_device(serial)
44
+ response = execute "/api/v1/user/devices/#{serial}", Net::HTTP::Delete
45
+ return response.success
46
+ end
47
+
48
+ def start_debug(serial)
49
+ response = execute "/api/v1//user/devices/#{serial}/remoteConnect", Net::HTTP::Post
50
+ return response
51
+ end
52
+
53
+ def stop_debug(serial)
54
+ response = execute "/api/v1//user/devices/#{serial}/remoteConnect", Net::HTTP::Delete
55
+ return response.success
56
+ end
57
+
58
+ private
59
+
60
+ def execute(relative_url, type, body='')
61
+ uri = URI.parse(@base_url + relative_url)
62
+ http = Net::HTTP.new(uri.host)
63
+ request = type.new(uri.request_uri, 'Authorization' => "Bearer #{@token}", 'Content-Type' => 'application/json')
64
+ request.body = body
65
+ response = http.request(request)
66
+
67
+
68
+ json = JSON.parse(response.body, object_class: OpenStruct)
69
+
70
+ logger.debug "API returned #{json}"
71
+
72
+ return json
73
+ end
74
+ end
75
+ end
data/lib/stf/errors.rb ADDED
@@ -0,0 +1,5 @@
1
+ class DeviceNotAvailableError < StandardError
2
+ def message
3
+ 'Device not available'
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ class RemoveAllUserDevicesInteractor
2
+
3
+ def initialize(stf)
4
+ @stf = stf
5
+ end
6
+
7
+ def execute
8
+ devices = @stf.get_user_devices
9
+ devices.each { |d| @stf.remove_device d.serial }
10
+ end
11
+ end
@@ -0,0 +1,65 @@
1
+ require 'ADB'
2
+
3
+ require 'stf/client'
4
+ require 'stf/log/log'
5
+ require 'stf/errors'
6
+ require 'stf/model/session'
7
+
8
+ class StartDebugSessionInteractor
9
+
10
+ include Log
11
+ include ADB
12
+
13
+ def initialize(stf)
14
+ @stf = stf
15
+ end
16
+
17
+ def execute
18
+ randomized_device = nil
19
+
20
+ 1..10.times do
21
+ begin
22
+ devices = @stf.get_devices
23
+ if devices.nil? || (devices.is_a?(Array) && devices.empty?)
24
+ logger.info 'No devices connected to STF. Retrying'
25
+ sleep 5
26
+ next
27
+ end
28
+ usable_devices = devices.select { |device| device.using == false }
29
+ if usable_devices.empty?
30
+ logger.error 'All devices are being used. Retrying'
31
+ sleep 5
32
+ next
33
+ end
34
+
35
+ randomized_device = usable_devices.sample
36
+ raise new DeviceNotAvailableError if randomized_device.nil?
37
+
38
+ serial = randomized_device.serial
39
+ success = @stf.add_device serial
40
+ if success
41
+ logger.info "Device #{serial} added"
42
+ elsif logger.error "Can't add device #{serial}. Retrying"
43
+ next
44
+ end
45
+
46
+ result = @stf.start_debug serial
47
+ if !result.success
48
+ logger.error "Can't start debugging session for device #{serial}. Retrying"
49
+ @stf.remove_device serial
50
+ next
51
+ end
52
+
53
+ execute_adb_with 30, "connect #{result.remoteConnectUrl}"
54
+
55
+ return Session.new(serial, result.remoteConnectUrl)
56
+ break
57
+
58
+ raise new DeviceNotAvailableError
59
+ rescue DeviceNotAvailableError
60
+ logger.error 'Failed to start debug session. Retrying...'
61
+ next
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,25 @@
1
+ require 'ADB'
2
+
3
+ require 'stf/client'
4
+ require 'stf/log/log'
5
+ require 'stf/errors'
6
+ require 'stf/interactor/stop_debug_session_interactor'
7
+
8
+ class StopAllDebugSessionsInteractor
9
+ include Log
10
+ include ADB
11
+
12
+ def initialize(stf)
13
+ @stf = stf
14
+ end
15
+
16
+ def execute
17
+ connected_devices = devices()
18
+ remote_devices = @stf.get_user_devices.map { |d| d.remoteConnectUrl }
19
+
20
+ pending_disconnect = connected_devices & remote_devices
21
+ pending_disconnect.each do |d|
22
+ StopDebugSessionInteractor.new(@stf).execute d
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,49 @@
1
+ require 'ADB'
2
+
3
+ require 'stf/client'
4
+ require 'stf/log/log'
5
+ require 'stf/errors'
6
+
7
+ class StopDebugSessionInteractor
8
+
9
+ include Log
10
+ include ADB
11
+
12
+ def initialize(stf)
13
+ @stf = stf
14
+ end
15
+
16
+ def execute(remoteConnectUrl)
17
+ remote_devices = @stf.get_user_devices
18
+ device = remote_devices.find { |d| d.remoteConnect == true && d.remoteConnectUrl.eql?(remoteConnectUrl) }
19
+
20
+ raise DeviceNotAvailableError if device.nil?
21
+
22
+ execute_adb_with 30, "disconnect #{device.remoteConnectUrl}"
23
+
24
+ success = false
25
+
26
+ 1..10.times do
27
+ success = @stf.stop_debug(device.serial)
28
+ if success == true
29
+ break
30
+ elsif logger.error 'Can\'t stop debug session. Retrying'
31
+ end
32
+ end
33
+
34
+ 1..10.times do
35
+ success = @stf.remove_device(device.serial)
36
+ if success == true
37
+ break
38
+ elsif logger.error 'Can\'t remove device from user devices. Retrying'
39
+ end
40
+ end
41
+
42
+ if success == true
43
+ logger.info "Successfully removed #{remoteConnectUrl}"
44
+ elsif logger.error "Error removing #{remoteConnectUrl}"
45
+ end
46
+
47
+ return success
48
+ end
49
+ end
@@ -0,0 +1,16 @@
1
+ require 'logger'
2
+
3
+ module Log
4
+
5
+ @@logger = Logger.new(STDOUT)
6
+ @@logger.level = Logger::INFO
7
+
8
+ def logger
9
+ @@logger
10
+ end
11
+
12
+ def self.verbose(enable)
13
+ @@logger.level = enable ? Logger::DEBUG : Logger::INFO
14
+ end
15
+
16
+ end
@@ -0,0 +1,10 @@
1
+ class Session
2
+
3
+ attr_accessor :serial, :url
4
+
5
+ def initialize(serial, url)
6
+ @serial = serial
7
+ @url = url
8
+ end
9
+
10
+ end
@@ -0,0 +1,3 @@
1
+ module Stf
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,67 @@
1
+ module Stf
2
+ module CLI
3
+ require 'gli'
4
+ require 'stf/client'
5
+
6
+ require 'stf/interactor/start_debug_session_interactor'
7
+ require 'stf/interactor/stop_debug_session_interactor'
8
+ require 'stf/interactor/stop_all_debug_sessions_interactor'
9
+ require 'stf/interactor/remove_all_user_devices_interactor'
10
+
11
+ include GLI::App
12
+ extend self
13
+
14
+ program_desc 'Smartphone Test Lab client'
15
+
16
+ desc 'Be verbose'
17
+ switch [:v, :verbose]
18
+
19
+ desc 'Authorization token'
20
+ flag [:t, :token]
21
+
22
+ desc 'URL to STF'
23
+ flag [:u, :url]
24
+
25
+ pre do |global_options, command, options, args|
26
+ help_now!('STF url is required') if global_options[:url].nil?
27
+ help_now!('Authorization token is required') if global_options[:token].nil?
28
+
29
+ Log::verbose(global_options[:verbose])
30
+
31
+ $stf = Stf::Client.new(global_options[:url], global_options[:token])
32
+ end
33
+
34
+ desc 'Search for a device available in STF and attach it to local adb server'
35
+ command :connect do |c|
36
+ c.action do |global_options, options, args|
37
+ StartDebugSessionInteractor.new($stf).execute
38
+ end
39
+ end
40
+
41
+ desc 'Disconnect device(s) from local adb server and remove device(s) from user devices in STF'
42
+ command :disconnect do |c|
43
+ c.desc '(optional) ADB connection url of the device'
44
+ c.flag [:d, :device]
45
+ c.switch [:all]
46
+
47
+ c.action do |global_options, options, args|
48
+ if options[:device].nil? && options[:all] == true
49
+ StopAllDebugSessionsInteractor.new($stf).execute
50
+ elsif !options[:device].nil? && options[:all] == false
51
+ StopDebugSessionInteractor.new($stf).execute(options[:device])
52
+ elsif help_now!('Please specify disconnect mode (-all or -device)')
53
+ end
54
+ end
55
+ end
56
+
57
+ desc 'Frees all devices that are assigned to current user in STF. Doesn\'t modify local adb'
58
+ command :clean do |c|
59
+ c.action do |global_options, options, args|
60
+ RemoveAllUserDevicesInteractor.new($stf).execute
61
+ end
62
+ end
63
+
64
+ exit run(ARGV)
65
+ end
66
+ end
67
+
data/lib/stf.rb ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'stf/view/cli'
4
+
5
+ module Stf
6
+ include Stf::CLI
7
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'stf/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'stf-client'
8
+ spec.version = Stf::VERSION
9
+ spec.authors = ['Anton Malinskiy']
10
+ spec.email = ['anton@malinskiy.com']
11
+ spec.summary = %q{Request devices from Smartphone Test Farm for adb connection}
12
+ spec.homepage = 'https://github.com/Malinskiy/stf-client'
13
+ spec.license = 'MIT'
14
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
15
+ spec.require_paths = ['lib']
16
+ spec.executables = ['stf-client']
17
+
18
+ spec.add_development_dependency 'bundler', '~> 1.12'
19
+ spec.add_development_dependency 'rake', '~> 10.0'
20
+ spec.add_development_dependency 'rspec', '~> 3.5'
21
+ spec.add_development_dependency 'webmock', '~> 2.1'
22
+ spec.add_development_dependency 'sinatra', '~> 1.4'
23
+ end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stf-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Anton Malinskiy
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-07-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.5'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: webmock
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: sinatra
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.4'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.4'
83
+ description:
84
+ email:
85
+ - anton@malinskiy.com
86
+ executables:
87
+ - stf-client
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - ".gitignore"
92
+ - ".rspec"
93
+ - Gemfile
94
+ - LICENSE.txt
95
+ - README.md
96
+ - Rakefile
97
+ - bin/setup
98
+ - bin/stf-client
99
+ - lib/stf.rb
100
+ - lib/stf/client.rb
101
+ - lib/stf/errors.rb
102
+ - lib/stf/interactor/remove_all_user_devices_interactor.rb
103
+ - lib/stf/interactor/start_debug_session_interactor.rb
104
+ - lib/stf/interactor/stop_all_debug_sessions_interactor.rb
105
+ - lib/stf/interactor/stop_debug_session_interactor.rb
106
+ - lib/stf/log/log.rb
107
+ - lib/stf/model/session.rb
108
+ - lib/stf/version.rb
109
+ - lib/stf/view/cli.rb
110
+ - stf-client.gemspec
111
+ homepage: https://github.com/Malinskiy/stf-client
112
+ licenses:
113
+ - MIT
114
+ metadata: {}
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 2.5.1
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: Request devices from Smartphone Test Farm for adb connection
135
+ test_files: []