testdroid-api-client 0.2.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +5 -0
- data/.travis.yml +11 -0
- data/Gemfile.lock +65 -37
- data/README.md +30 -41
- data/lib/testdroid-api-client.rb +25 -9
- data/lib/testdroid-api-filter-builder.rb +145 -0
- data/lib/testdroid_api/admin.rb +25 -0
- data/lib/testdroid_api/admin_device_models.rb +10 -0
- data/lib/testdroid_api/admin_device_problems.rb +9 -0
- data/lib/testdroid_api/admin_device_statuses.rb +12 -0
- data/lib/testdroid_api/admin_devices.rb +10 -0
- data/lib/testdroid_api/apikey_client.rb +120 -0
- data/lib/testdroid_api/client.rb +158 -123
- data/lib/testdroid_api/cloud_list_resource.rb +69 -70
- data/lib/testdroid_api/cloud_resource.rb +83 -71
- data/lib/testdroid_api/device_groups.rb +9 -9
- data/lib/testdroid_api/device_session_connections.rb +10 -0
- data/lib/testdroid_api/device_sessions.rb +21 -12
- data/lib/testdroid_api/devices.rb +8 -11
- data/lib/testdroid_api/files.rb +60 -58
- data/lib/testdroid_api/frameworks.rb +11 -0
- data/lib/testdroid_api/label_groups.rb +9 -10
- data/lib/testdroid_api/labels.rb +9 -10
- data/lib/testdroid_api/projects.rb +9 -16
- data/lib/testdroid_api/properties.rb +13 -0
- data/lib/testdroid_api/runs.rb +22 -12
- data/lib/testdroid_api/services.rb +18 -0
- data/lib/testdroid_api/user.rb +11 -6
- data/sample/BitbarSampleApp.apk +0 -0
- data/sample/BitbarSampleAppTest.apk +0 -0
- data/sample/sample.rb +23 -23
- data/spec/client_spec.rb +7 -7
- data/spec/device_groups_spec.rb +30 -17
- data/spec/files_spec.rb +40 -20
- data/spec/fixtures/apk.apk +0 -0
- data/spec/fixtures/cassettes/device_groups_authorize.json +1 -0
- data/spec/fixtures/cassettes/device_groups_create.json +1 -0
- data/spec/fixtures/cassettes/device_groups_delete.json +1 -0
- data/spec/fixtures/cassettes/device_groups_get_all.json +1 -0
- data/spec/fixtures/cassettes/device_groups_get_one.json +1 -0
- data/spec/fixtures/cassettes/files_authorize.json +1 -0
- data/spec/fixtures/cassettes/files_delete.json +1 -0
- data/spec/fixtures/cassettes/files_get_all.json +1 -0
- data/spec/fixtures/cassettes/files_get_one.json +1 -0
- data/spec/fixtures/cassettes/files_upload.json +1 -0
- data/spec/fixtures/cassettes/files_upload_with_wait.json +1 -0
- data/spec/fixtures/cassettes/label_groups_authorize.json +1 -0
- data/spec/fixtures/cassettes/label_groups_create.json +1 -0
- data/spec/fixtures/cassettes/label_groups_delete.json +1 -0
- data/spec/fixtures/cassettes/label_groups_get_all.json +1 -0
- data/spec/fixtures/cassettes/label_groups_get_labels.json +1 -0
- data/spec/fixtures/cassettes/label_groups_get_one.json +1 -0
- data/spec/fixtures/cassettes/projects_authorize.json +1 -0
- data/spec/fixtures/cassettes/projects_create.json +1 -0
- data/spec/fixtures/cassettes/projects_delete.json +1 -0
- data/spec/fixtures/cassettes/projects_get_all.json +1 -0
- data/spec/fixtures/cassettes/projects_get_one.json +1 -0
- data/spec/fixtures/cassettes/runs_abort_run.json +1 -0
- data/spec/fixtures/cassettes/runs_authorize.json +1 -0
- data/spec/fixtures/cassettes/runs_get_project_runs.json +1 -0
- data/spec/fixtures/cassettes/runs_start_run.json +1 -0
- data/spec/fixtures/data.txt +1 -0
- data/spec/fixtures/data2.txt +1 -0
- data/spec/label_groups_spec.rb +35 -42
- data/spec/projects_spec.rb +41 -0
- data/spec/runs_spec.rb +41 -0
- data/spec/spec_helper.rb +3 -4
- data/testdroid-api-client.gemspec +13 -11
- metadata +92 -134
- data/lib/testdroid_api/config.rb +0 -7
- data/lib/testdroid_api/device_runs.rb +0 -20
- data/lib/testdroid_api/file_sets.rb +0 -12
- data/spec/device_runs_spec.rb +0 -25
- data/spec/file_sets_spec.rb +0 -47
- data/spec/fixtures/cassettes/dg_all_device_groups.json +0 -1
- data/spec/fixtures/cassettes/dg_device_group_4165.json +0 -1
- data/spec/fixtures/cassettes/dg_oauth2_auth_device_groups.json +0 -1
- data/spec/fixtures/cassettes/dr_all_run_171221_device_runs.json +0 -1
- data/spec/fixtures/cassettes/dr_device_run_33044722.json +0 -1
- data/spec/fixtures/cassettes/dr_oauth2_auth_device_runs.json +0 -1
- data/spec/fixtures/cassettes/dr_run_33044722_device_runs.json +0 -1
- data/spec/fixtures/cassettes/f_add_file_set.json +0 -1
- data/spec/fixtures/cassettes/f_android_app_file.json +0 -1
- data/spec/fixtures/cassettes/f_file_sets.json +0 -1
- data/spec/fixtures/cassettes/f_oauth2_auth_files.json +0 -1
- data/spec/fixtures/cassettes/f_upload_files.json +0 -1
- data/spec/fixtures/cassettes/fs_add_file_set.json +0 -1
- data/spec/fixtures/cassettes/fs_add_file_to_fileset.json +0 -1
- data/spec/fixtures/cassettes/fs_delete_file_set.json +0 -1
- data/spec/fixtures/cassettes/fs_file_sets.json +0 -1
- data/spec/fixtures/cassettes/fs_get_file_set.json +0 -1
- data/spec/fixtures/cassettes/fs_oauth2_auth_files.json +0 -1
- data/spec/fixtures/cassettes/fs_update_file_set.json +0 -1
- data/spec/fixtures/cassettes/fu_oauth2_auth_files.json +0 -1
- data/spec/fixtures/cassettes/lg_all_label_groups.json +0 -1
- data/spec/fixtures/cassettes/lg_get_resources_by_label.json +0 -1
- data/spec/fixtures/cassettes/lg_label_group_1058800.json +0 -1
- data/spec/fixtures/cassettes/lg_labels_of_group_1058800.json +0 -1
- data/spec/fixtures/cassettes/lg_oauth2_auth_label_groups.json +0 -1
- data/spec/fixtures/cassettes/p_all_projects.json +0 -1
- data/spec/fixtures/cassettes/p_create_project.json +0 -1
- data/spec/fixtures/cassettes/p_get_run_devices.json +0 -1
- data/spec/fixtures/cassettes/p_oauth2_auth.json +0 -1
- data/spec/fixtures/cassettes/p_oauth2_local.json +0 -1
- data/spec/fixtures/cassettes/p_project_id_33029366.json +0 -1
- data/spec/fixtures/cassettes/p_run_project.json +0 -1
- data/spec/fixtures/cassettes/pc_get_current.json +0 -1
- data/spec/fixtures/cassettes/pc_oauth2_auth_config.json +0 -1
- data/spec/fixtures/cassettes/pc_set_current_config.json +0 -1
- data/spec/fixtures/cassettes/pc_validate_config.json +0 -1
- data/spec/fixtures/cassettes/r_all_project_33029366_runs.json +0 -1
- data/spec/fixtures/cassettes/r_delete_test_run.json +0 -1
- data/spec/fixtures/cassettes/r_oauth2_auth_runs.json +0 -1
- data/spec/fixtures/cassettes/r_run_171221.json +0 -1
- data/spec/fixtures/cassettes/r_run_project.json +0 -1
- data/spec/fixtures/cassettes/upload_files.json +0 -1
- data/spec/fixtures/project.json +0 -8
- data/spec/project_config_spec.rb +0 -36
- data/spec/project_spec.rb +0 -56
- data/spec/run_spec.rb +0 -33
@@ -1,83 +1,82 @@
|
|
1
|
-
|
2
1
|
module TestdroidAPI
|
3
|
-
|
2
|
+
class CloudListResource
|
3
|
+
|
4
|
+
def initialize(uri, client, instance_class = nil)
|
5
|
+
@uri, @client = uri, client
|
6
|
+
resource_name = self.class.name.split('::')[-1]
|
7
|
+
@instance_class = TestdroidAPI.const_get(instance_class.nil? ? resource_name.chop : instance_class)
|
8
|
+
@list_key, @instance_id_key = resource_name.gsub!(/\b\w/) {$&.downcase}, 'id'
|
9
|
+
end
|
4
10
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
@instance_class = TestdroidAPI.const_get resource_name.chop
|
9
|
-
@list_key, @instance_id_key = resource_name.gsub!(/\b\w/) { $&.downcase } , 'id'
|
10
|
-
end
|
11
|
-
def get(resource_id)
|
12
|
-
@instance_class.new( "#{@uri}/#{resource_id}", @client)
|
13
|
-
end
|
14
|
-
def total
|
11
|
+
def get(resource_id)
|
12
|
+
@instance_class.new("#{@uri}/#{resource_id}", @client)
|
13
|
+
end
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
raise "Can't create a resource without a REST Client" unless @client
|
20
|
-
response = @client.post @uri, params
|
21
|
-
@instance_class.new "#{@uri}/#{response[@instance_id_key]}", @client,
|
22
|
-
response
|
23
|
-
end
|
24
|
-
def list_all()
|
25
|
-
raise "Can't get a resource list without a REST Client" unless @client
|
15
|
+
def total
|
16
|
+
@client.get(@uri)['total']
|
17
|
+
end
|
26
18
|
|
27
|
-
|
19
|
+
def create(params = {})
|
20
|
+
raise "Can't create a resource without a REST Client" unless @client
|
21
|
+
response = @client.post @uri, params
|
22
|
+
@instance_class.new "#{@uri}/#{response[@instance_id_key]}", @client, response
|
23
|
+
end
|
28
24
|
|
29
|
-
|
30
|
-
|
31
|
-
class_list = []
|
32
|
-
list_class = self.class
|
33
|
-
instance_uri = @uri
|
34
|
-
response['data'].each do |val|
|
25
|
+
def list_all()
|
26
|
+
raise "Can't get a resource list without a REST Client" unless @client
|
35
27
|
|
36
|
-
|
37
|
-
end
|
38
|
-
end
|
39
|
-
class_list
|
40
|
-
end
|
41
|
-
def list(params={}, full_uri=false)
|
42
|
-
raise "Can't get a resource list without a REST Client" unless @client
|
43
|
-
@uri = full_uri ? @uri.split(@client.instance_variable_get(:@cloud_url))[1] : @uri
|
28
|
+
response = @client.get(@uri, {:limit => 0})
|
44
29
|
|
45
|
-
|
30
|
+
class_list = []
|
31
|
+
if response['data'].is_a?(Array)
|
32
|
+
instance_uri = @uri
|
33
|
+
response['data'].each do |val|
|
34
|
+
class_list << @instance_class.new("#{instance_uri}/#{val[@instance_id_key]}", @client, val)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
class_list
|
38
|
+
end
|
46
39
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
40
|
+
def list(params = {}, full_uri = false)
|
41
|
+
raise "Can't get a resource list without a REST Client" unless @client
|
42
|
+
@uri = full_uri ? @uri.split(@client.instance_variable_get(:@cloud_url))[1] : @uri
|
43
|
+
response = @client.get(@uri, params)
|
44
|
+
class_list = []
|
45
|
+
if response['data'].is_a?(Array)
|
46
|
+
client = @client
|
47
|
+
list_class = self.class
|
48
|
+
instance_uri = full_uri ? @uri.split('?')[0] : @uri
|
49
|
+
response['data'].each do |val|
|
53
50
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
51
|
+
class_list << @instance_class.new("#{instance_uri}/#{val[@instance_id_key]}", @client, val)
|
52
|
+
end
|
53
|
+
class_list.instance_eval do
|
54
|
+
eigenclass = class << self;
|
55
|
+
self;
|
56
|
+
end
|
58
57
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
58
|
+
eigenclass.send :define_method, :offset, &lambda {response['offset']}
|
59
|
+
eigenclass.send :define_method, :limit, &lambda {response['limit']}
|
60
|
+
eigenclass.send :define_method, :total, &lambda {response['total']}
|
61
|
+
eigenclass.send :define_method, :next_page, &lambda {
|
62
|
+
if response['next']
|
64
63
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
64
|
+
list_class.new(response['next'], client).list({}, true)
|
65
|
+
else
|
66
|
+
[]
|
67
|
+
end
|
68
|
+
}
|
69
|
+
eigenclass.send :define_method, :previous_page, &lambda {
|
70
|
+
if response['previous']
|
72
71
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
72
|
+
list_class.new(response['previous'], client).list({}, true)
|
73
|
+
else
|
74
|
+
[]
|
75
|
+
end
|
76
|
+
}
|
77
|
+
end
|
78
|
+
end
|
79
|
+
class_list
|
80
|
+
end
|
81
|
+
end
|
83
82
|
end
|
@@ -1,77 +1,89 @@
|
|
1
|
-
|
2
1
|
module TestdroidAPI
|
3
|
-
|
4
|
-
|
2
|
+
class CloudResource
|
3
|
+
def initialize(uri, client, resource_name = nil, params = {})
|
4
|
+
|
5
|
+
@uri, @client, @resource_name = uri, client, resource_name
|
6
|
+
set_up_properties_from(params)
|
7
|
+
end
|
8
|
+
|
9
|
+
def inspect # :nodoc:
|
10
|
+
"<#{self.class} @uri=#{@uri}>"
|
11
|
+
end
|
12
|
+
|
13
|
+
def sub_items(*items)
|
14
|
+
items.each do |item|
|
15
|
+
resource = camel_case_it item
|
16
|
+
uri = "#{@uri}/#{item.to_s.gsub('_', '-') }"
|
17
|
+
resource_class = TestdroidAPI.const_get resource
|
18
|
+
new_class = resource_class.new(uri, @client)
|
19
|
+
instance_variable_set("@#{item}", new_class)
|
20
|
+
end
|
21
|
+
self.class.instance_eval {attr_reader *items}
|
22
|
+
end
|
23
|
+
|
24
|
+
def method_missing(method, *args)
|
25
|
+
super if @updated
|
26
|
+
set_up_properties_from(@client.get(@uri))
|
27
|
+
self.send method, *args
|
28
|
+
end
|
29
|
+
|
30
|
+
def update(params = {})
|
31
|
+
raise "Can't update a resource without a REST Client" unless @client
|
32
|
+
set_up_properties_from(@client.post(@uri, params))
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def set_up_properties_from(hash)
|
37
|
+
|
38
|
+
eigenclass = class << self;
|
39
|
+
self;
|
40
|
+
end
|
41
|
+
hash.each do |p, v|
|
42
|
+
property = snake_case_it p
|
43
|
+
|
44
|
+
unless ['uri', 'client', 'updated'].include? property
|
45
|
+
eigenclass.send :define_method, property.to_sym, &lambda {v}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
@updated = !hash.keys.empty?
|
49
|
+
end
|
50
|
+
|
51
|
+
def refresh
|
52
|
+
raise "Can't refresh a resource without a REST Client" unless @client
|
53
|
+
@updated = false
|
54
|
+
set_up_properties_from(@client.get(@uri))
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
alias_method :load, :refresh
|
5
59
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
12
|
-
def sub_items(*items)
|
13
|
-
items.each do |item|
|
14
|
-
resource = camel_case_it item
|
15
|
-
uri = "#{@uri}/#{item.to_s.gsub('_', '-') }"
|
16
|
-
resource_class = TestdroidAPI.const_get resource
|
17
|
-
new_class = resource_class.new(uri, @client)
|
18
|
-
instance_variable_set( "@#{item}", new_class )
|
19
|
-
end
|
20
|
-
self.class.instance_eval {attr_reader *items}
|
21
|
-
end
|
22
|
-
def method_missing(method, *args)
|
23
|
-
super if @updated
|
24
|
-
set_up_properties_from(@client.get(@uri))
|
25
|
-
self.send method, *args
|
26
|
-
end
|
27
|
-
def update(params = {})
|
28
|
-
raise "Can't update a resource without a REST Client" unless @client
|
29
|
-
set_up_properties_from(@client.post(@uri, params))
|
30
|
-
self
|
31
|
-
end
|
32
|
-
def set_up_properties_from(hash)
|
60
|
+
def download_file(file_resource_name, target_file_name = nil)
|
61
|
+
raise "Can't refresh a resource without a REST Client" unless @client
|
62
|
+
target_file_name = file_resource_name unless target_file_name
|
63
|
+
@client.download("#{@uri}/#{file_resource_name}", target_file_name)
|
64
|
+
end
|
33
65
|
|
34
|
-
|
35
|
-
|
36
|
-
|
66
|
+
def camel_case_it(something)
|
67
|
+
if something.is_a? Hash
|
68
|
+
Hash[*something.to_a.map {|a| [camel_case_it(a[0]).to_sym, a[1]]}.flatten]
|
69
|
+
else
|
70
|
+
something.to_s.split('_').map do |s|
|
71
|
+
[s[0, 1].capitalize, s[1..-1]].join
|
72
|
+
end.join
|
73
|
+
end
|
74
|
+
end
|
37
75
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
76
|
+
def snake_case_it(something)
|
77
|
+
if something.is_a? Hash
|
78
|
+
Hash[*something.to_a.map {|pair| [snake_case_it(pair[0]).to_sym, pair[1]]}.flatten]
|
79
|
+
else
|
80
|
+
something.to_s.gsub(/[A-Z][a-z]*/) {|s| "_#{s.downcase}"}.gsub(/^_/, '')
|
81
|
+
end
|
82
|
+
end
|
44
83
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
51
|
-
def download_file(file_resource_name, target_file_name=nil)
|
52
|
-
raise "Can't refresh a resource without a REST Client" unless @client
|
53
|
-
target_file_name = file_resource_name unless target_file_name
|
54
|
-
@client.download("#{@uri}/#{file_resource_name}", target_file_name)
|
55
|
-
end
|
56
|
-
def camel_case_it(something)
|
57
|
-
if something.is_a? Hash
|
58
|
-
Hash[*something.to_a.map {|a| [camel_case_it(a[0]).to_sym, a[1]]}.flatten]
|
59
|
-
else
|
60
|
-
something.to_s.split('_').map do |s|
|
61
|
-
[s[0,1].capitalize, s[1..-1]].join
|
62
|
-
end.join
|
63
|
-
end
|
64
|
-
end
|
65
|
-
def snake_case_it(something)
|
66
|
-
if something.is_a? Hash
|
67
|
-
Hash[*something.to_a.map {|pair| [snake_case_it(pair[0]).to_sym, pair[1]]}.flatten]
|
68
|
-
else
|
69
|
-
something.to_s.gsub(/[A-Z][a-z]*/) {|s| "_#{s.downcase}"}.gsub(/^_/, '')
|
70
|
-
end
|
71
|
-
end
|
72
|
-
def delete
|
73
|
-
raise "Can't delete a resource without a REST Client" unless @client
|
74
|
-
@client.delete(@uri)
|
75
|
-
end
|
76
|
-
end
|
84
|
+
def delete
|
85
|
+
raise "Can't delete a resource without a REST Client" unless @client
|
86
|
+
@client.delete(@uri)
|
87
|
+
end
|
88
|
+
end
|
77
89
|
end
|
@@ -1,12 +1,12 @@
|
|
1
|
-
|
2
1
|
module TestdroidAPI
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
2
|
+
class DeviceGroups < CloudListResource
|
3
|
+
end
|
4
|
+
class DeviceGroup < CloudResource
|
5
|
+
def initialize(uri, client, params = {})
|
6
|
+
super uri, client, "deviceGroup", params
|
7
|
+
@uri, @client = uri, client
|
8
|
+
sub_items :devices
|
9
|
+
end
|
10
10
|
|
11
|
-
|
11
|
+
end
|
12
12
|
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module TestdroidAPI
|
2
|
+
class DeviceSessionConnections < CloudListResource
|
3
|
+
end
|
4
|
+
class DeviceSessionConnection < CloudResource
|
5
|
+
def initialize(uri, client, params = {})
|
6
|
+
super uri, client, "DeviceSessionConnection", params
|
7
|
+
@uri, @client = uri, client
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -1,14 +1,23 @@
|
|
1
|
-
|
2
1
|
module TestdroidAPI
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
2
|
+
class DeviceSessions < CloudListResource
|
3
|
+
end
|
4
|
+
class DeviceSession < CloudResource
|
5
|
+
def initialize(uri, client, params = {})
|
6
|
+
super uri, client, "deviceSession", params
|
7
|
+
@uri, @client = uri, client
|
8
|
+
end
|
9
|
+
|
10
|
+
def release
|
11
|
+
@client.post("#{@uri}/release", params = {})
|
12
|
+
end
|
13
|
+
|
14
|
+
def download_all_files(path)
|
15
|
+
Dir.mkdir(path) unless Dir.exist?(path)
|
16
|
+
files = @client.get("#{@uri}/output-file-set/files")
|
17
|
+
files['data'].each do |file|
|
18
|
+
@client.download(file['directUrl'], ::File.join(path, "#{file['id']}-#{file['name']}"))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
14
23
|
end
|
@@ -1,13 +1,10 @@
|
|
1
|
-
|
2
1
|
module TestdroidAPI
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
end
|
2
|
+
class Devices < CloudListResource
|
3
|
+
end
|
4
|
+
class Device < CloudResource
|
5
|
+
def initialize(uri, client, params = {})
|
6
|
+
super uri, client, "device", params
|
7
|
+
@uri, @client = uri, client
|
8
|
+
end
|
9
|
+
end
|
13
10
|
end
|
data/lib/testdroid_api/files.rb
CHANGED
@@ -1,60 +1,62 @@
|
|
1
|
-
|
2
1
|
module TestdroidAPI
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
2
|
+
class Files < CloudListResource
|
3
|
+
|
4
|
+
ACCEPTED_VIRUS_SCAN_STATUSES = Set['safe', 'disabled', nil]
|
5
|
+
|
6
|
+
def upload(filename, skip_scan_wait=false)
|
7
|
+
unless ::File.exist?(filename)
|
8
|
+
@client.logger.error("Invalid filename")
|
9
|
+
return
|
10
|
+
end
|
11
|
+
file = @client.upload("#{@uri}", filename)
|
12
|
+
result = File.new("#{@uri}/#{file['id']}", @client, file)
|
13
|
+
if !skip_scan_wait
|
14
|
+
wait_for_virus_scan(Array(result))
|
15
|
+
end
|
16
|
+
return result
|
17
|
+
end
|
18
|
+
|
19
|
+
def wait_for_virus_scan(api_files, timeout=300)
|
20
|
+
all_safe = false
|
21
|
+
begin
|
22
|
+
Timeout.timeout(timeout) do
|
23
|
+
while !all_safe do
|
24
|
+
statuses = Set.new
|
25
|
+
api_files.each do |file|
|
26
|
+
current_status = get_virus_scan_status(file)
|
27
|
+
if ACCEPTED_VIRUS_SCAN_STATUSES.include?(current_status)
|
28
|
+
statuses.add(current_status)
|
29
|
+
else
|
30
|
+
sleep(1)
|
31
|
+
file.refresh
|
32
|
+
statuses.add(get_virus_scan_status(file))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
if statuses.include?('infected')
|
36
|
+
raise 'File rejected by virus scan'
|
37
|
+
end
|
38
|
+
if ACCEPTED_VIRUS_SCAN_STATUSES.superset?(statuses)
|
39
|
+
all_safe = true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
rescue Timeout::Error
|
44
|
+
@client.logger.error("Waiting for virus scan timed out")
|
45
|
+
raise
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def get_virus_scan_status(file)
|
52
|
+
return file.file_properties.find{ |item| item['key'] == "virus_scan_status" }['value']
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class File < CloudResource
|
57
|
+
def initialize(uri, client, params = {})
|
58
|
+
super uri, client, "file", params
|
59
|
+
@uri, @client = uri, client
|
60
|
+
end
|
61
|
+
end
|
60
62
|
end
|