xamarin-test-cloud 0.9.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: eb0063f60324d962136569cbb02a120355c4a9b3
4
+ data.tar.gz: c3f3a4eafe87aa4ee3a2e750cdd92144ac50b86c
5
+ SHA512:
6
+ metadata.gz: 94064d3747ab099c6f042106f6bb93ad69d4bb1bba70cdef9223be64539d48334bf1a66aac47d4457963823d09990e36e6b04df7d38c1ea4c0a4d1652d20fa7f
7
+ data.tar.gz: f0c598d9d96dc52303cb2b3e52425aa3bc1cf3b794fd7f3abbf5ee9a89c022ee143da830abef93711eb3b85b27bacad34976419a9221de3bda3fa17310712e7a
data/CHANGES.txt ADDED
@@ -0,0 +1,2 @@
1
+ 0.9.0 Initial beta
2
+ Supports upload of Calabash test suites to https://testcloud.xamarin.com.
data/README.md ADDED
File without changes
data/bin/test-cloud ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ require 'xamarin-test-cloud/cli'
3
+
4
+ begin
5
+ ENV['THOR_DEBUG'] = '1'
6
+ XamarinTestCloud::CLI.start
7
+ exit(true)
8
+ rescue XamarinTestCloud::ValidationError, Thor::RequiredArgumentMissingError, Thor::UndefinedCommandError => e
9
+ puts e.message
10
+ exit 64
11
+ rescue Thor::Error => e
12
+ puts e.message
13
+ if ENV['DEBUG'] == '1'
14
+ puts e.backtrace.join("\n") if e.backtrace
15
+ p e.class
16
+ end
17
+ exit 70
18
+ end
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+ gem 'calabash-android'
3
+
data/lib/GemfileIOS ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+ gem 'calabash-cucumber'
3
+
@@ -0,0 +1,618 @@
1
+ require 'thor'
2
+ require 'yaml'
3
+ require 'rubygems'
4
+ require 'zip/zip'
5
+ require 'digest'
6
+ require 'rest_client'
7
+ require 'json'
8
+ require 'rbconfig'
9
+ require 'tmpdir'
10
+ require 'fileutils'
11
+
12
+ module XamarinTestCloud
13
+
14
+ class ValidationError < Thor::InvocationError
15
+ end
16
+
17
+ class CLI < Thor
18
+ include Thor::Actions
19
+
20
+ attr_accessor :host, :app, :api_key, :appname, :workspace, :config, :profile, :features_zip, :skip_check, :dry_run, :device_selection
21
+ attr_accessor :pretty
22
+ attr_accessor :endpoint_path
23
+
24
+ FILE_UPLOAD_ENDPOINT = 'upload2'
25
+ FORM_URL_ENCODED_ENDPOINT = 'upload'
26
+
27
+
28
+ def self.source_root
29
+ File.join(File.dirname(__FILE__), '..')
30
+ end
31
+
32
+ desc 'version', 'Prints version of the xamarin-test-cloud gem'
33
+
34
+ def version
35
+ puts XamarinTestCloud::VERSION
36
+ end
37
+
38
+ desc 'submit <APP> <API_KEY>', 'Submits your app and test suite to Xamarin Test Cloud'
39
+
40
+ method_option :host,
41
+ :desc => 'Test Cloud host to submit to',
42
+ :aliases => '-h', :type => :string,
43
+ :default => (ENV['XTC_ENDPOINT'] || 'https://testcloud.xamarin.com/ci')
44
+
45
+ method_option 'app-name',
46
+ :desc => 'App name to create or add test to',
47
+ :aliases => '-a',
48
+ :required => true,
49
+ :type => :string
50
+
51
+ method_option 'device-selection',
52
+ :desc => 'Device selection',
53
+ :aliases => '-d',
54
+ :required => true,
55
+ :type => :string
56
+
57
+ method_option :workspace,
58
+ :desc => 'Workspace containing Gemfile and features',
59
+ :aliases => '-w',
60
+ :type => :string,
61
+ :default => File.expand_path('.')
62
+
63
+ method_option :features,
64
+ :desc => 'Zip file with features, step definitions, etc...',
65
+ :aliases => '-f',
66
+ :type => :string
67
+
68
+ method_option :config,
69
+ :desc => 'Cucumber configuration file (cucumber.yml)',
70
+ :aliases => '-c',
71
+ :type => :string
72
+
73
+ method_option :profile,
74
+ :desc => 'Profile to run (profile from cucumber.yml)',
75
+ :aliases => '-p',
76
+ :type => :string
77
+
78
+ method_option :pretty,
79
+ :desc => 'Pretty print output.',
80
+ :type => :boolean,
81
+ :default => false
82
+
83
+ method_option 'skip-check',
84
+ :desc => 'Skip checking for ipa linked with Calabash (iOS only)',
85
+ :type => :boolean
86
+
87
+ method_option 'dry-run',
88
+ :desc => "Sanity check only, don't upload",
89
+ :aliases => '-d',
90
+ :type => :boolean,
91
+ :default => false #do upload by default
92
+
93
+ def submit(app, api_key)
94
+
95
+ self.host = options[:host]
96
+
97
+ self.pretty = options[:pretty]
98
+
99
+ app_path = File.expand_path(app)
100
+ unless File.exist?(app_path)
101
+ raise ValidationError, "App is not a file: #{app_path}"
102
+ end
103
+
104
+ self.app = app_path
105
+
106
+ self.dry_run = options['dry-run']
107
+
108
+ self.api_key = api_key
109
+
110
+ self.appname = options['app-name']
111
+
112
+ self.device_selection = options['device-selection']
113
+ unless File.exist?(device_selection)
114
+ raise ValidationError, "Device selection is not a file: #{device_selection}"
115
+ end
116
+
117
+ self.skip_check = options['skip-check']
118
+
119
+ parse_and_set_config_and_profile
120
+
121
+ workspace_path = options[:workspace] || File.expand_path('.')
122
+
123
+ unless File.directory?(workspace_path)
124
+ raise ValidationError, "Provided workspace: #{workspace_path} is not a directory."
125
+ end
126
+ self.workspace = File.join(File.expand_path(workspace_path), File::Separator)
127
+
128
+ features_path = options[:features]
129
+
130
+ unless features_path.nil?
131
+ if File.exist?(features_path)
132
+ self.features_zip = File.expand_path(features_path)
133
+ else
134
+ raise ValidationError, "Provided features file does not exist #{features_path}"
135
+ end
136
+ end
137
+
138
+ if ENV['DEBUG']
139
+ puts "Host = #{self.host}"
140
+ puts "App = #{self.app}"
141
+ puts "App Name = #{self.app}"
142
+ puts "API Key = #{self.api_key}"
143
+ puts "Device Selection = #{self.device_selection}"
144
+ puts "Workspace = #{self.workspace}"
145
+ puts "Features Zip = #{self.features_zip}"
146
+ puts "Config = #{self.config}"
147
+ puts "Profile = #{self.profile}"
148
+ puts "Skip Check = #{self.skip_check}"
149
+ end
150
+
151
+ #Argument parsing done
152
+ json = submit_test_job[:body]
153
+ log_header("Test enqueued")
154
+ puts "User: #{json["user_email"]}"
155
+
156
+ puts "Devices:"
157
+ json["devices"].each do |device|
158
+ puts device
159
+ end
160
+ puts ""
161
+
162
+
163
+ result = wait_for_job(json["id"])
164
+
165
+ end
166
+
167
+ default_task :submit
168
+
169
+ no_tasks do
170
+
171
+ def exit_on_failure?
172
+ true
173
+ end
174
+
175
+ def wait_for_job(id)
176
+ while(true)
177
+ status_json = JSON.parse(http_post("status", {'id' => id, 'api_key' => api_key}))
178
+
179
+ log "Status: #{status_json["status_description"]}"
180
+ if status_json["status"] == "finished"
181
+ puts "Done!"
182
+ exit 0
183
+ end
184
+
185
+ if ["cancelled", "invalid"].include?(status_json["status"])
186
+ puts "Failed!"
187
+ exit 1
188
+ end
189
+ sleep 10
190
+ end
191
+ end
192
+
193
+
194
+ def submit_test_job
195
+ start_at = Time.now
196
+
197
+ server = verify_app_and_extract_test_server
198
+
199
+
200
+ log_header('Checking for Gemfile')
201
+ gemfile_path = File.join(self.workspace, 'Gemfile')
202
+ unless File.exist?(gemfile_path)
203
+ copy_default_gemfile(gemfile_path, server)
204
+ end
205
+
206
+ log_header('Packaging')
207
+ FileUtils.cd(self.workspace) do
208
+ unless system('bundle package --all')
209
+ log_and_abort 'Bundler failed. Please check command: bundle package'
210
+ end
211
+ end
212
+
213
+
214
+ log_header('Verifying dependencies')
215
+ verify_dependencies
216
+
217
+
218
+ if dry_run
219
+ log_header('Dry run only')
220
+ log('Dry run completed OK')
221
+ return
222
+ end
223
+
224
+ app_file, files, paths = gather_files_and_paths_to_upload(all_files)
225
+
226
+
227
+ log_header('Uploading negotiated files')
228
+
229
+ upload_data = {'files' => files,
230
+ 'paths' => paths,
231
+ 'app_file' => app_file,
232
+ 'device_selection' => IO.read(device_selection),
233
+ 'app' => self.appname,
234
+ 'api_key' => api_key,
235
+ 'app_filename' => File.basename(app)}
236
+
237
+ if profile #only if config and profile
238
+ upload_data['profile'] = profile
239
+ end
240
+
241
+ if ENV['DEBUG']
242
+ puts JSON.pretty_generate(upload_data)
243
+ end
244
+
245
+
246
+ contains_file = files.find { |f| f.is_a?(File) }
247
+
248
+ contains_file = contains_file || app_file.is_a?(File)
249
+
250
+ if contains_file
251
+ self.endpoint_path = FILE_UPLOAD_ENDPOINT #nginx receives upload
252
+ else
253
+ self.endpoint_path = FORM_URL_ENCODED_ENDPOINT #ruby receives upload
254
+ end
255
+
256
+ if ENV['DEBUG']
257
+ puts "Will upload to file path: #{self.endpoint_path}"
258
+ end
259
+
260
+
261
+ response = http_post(endpoint_path, upload_data) do |response, request, result, &block|
262
+ if ENV['DEBUG']
263
+ puts "Request url: #{request.url}"
264
+ puts "Response code: #{response.code}"
265
+ end
266
+ case response.code
267
+ when 200..202
268
+ response
269
+ when 403
270
+ abort do
271
+ puts 'Invalid API key'
272
+ end
273
+ when 413
274
+ abort do
275
+ puts 'Files too large'
276
+ end
277
+ else
278
+ abort do
279
+ log 'Unexpected Error. Please contact support at testcloud@xamarin.com.'
280
+ end
281
+ end
282
+ end
283
+
284
+ return :status => response.code, :body => JSON.parse(response)
285
+ end
286
+
287
+
288
+ def copy_default_gemfile(gemfile_path, server)
289
+ log('')
290
+ log('Gemfile missing.')
291
+ log('You must provide a Gemfile in your workspace.')
292
+ log('A Gemfile must describe your dependencies and their versions')
293
+ log('See: http://gembundler.com/v1.3/gemfile.html')
294
+ log('')
295
+ log('Warning proceeding with default Gemfile.')
296
+ log('It is strongly recommended that you create a custom Gemfile.')
297
+ tgt = nil
298
+ if is_android?
299
+ log('Creating Gemfile for Android')
300
+ tgt = File.join(CLI.source_root, 'GemfileAndroid')
301
+ elsif is_ios?
302
+ log('Creating Gemfile for iOS')
303
+ gemfile = 'GemfileIOS'
304
+ if server == :frank
305
+ raise ValidationError, 'Frank not supported just yet'
306
+ end
307
+ tgt = File.join(CLI.source_root, gemfile)
308
+ else
309
+ raise ValidationError, 'Your app must be an ipa or apk file.'
310
+ end
311
+ log("Proceeding with Gemfile: #{gemfile_path}")
312
+
313
+
314
+ FileUtils.cp(File.expand_path(tgt), gemfile_path)
315
+
316
+ puts(File.read(gemfile_path))
317
+
318
+ log('')
319
+
320
+ end
321
+
322
+ def gather_files_and_paths_to_upload(collected_files)
323
+
324
+ log_header('Calculating digests')
325
+
326
+ file_paths = collected_files[:files]
327
+ feature_prefix = collected_files[:feature_prefix]
328
+ workspace_prefix = collected_files[:workspace_prefix]
329
+
330
+ hashes = file_paths.collect { |f| digest(f) }
331
+ hashes << digest(app)
332
+
333
+
334
+ log_header('Negotiating upload')
335
+
336
+ response = http_post('check_hash', {'hashes' => hashes})
337
+
338
+ cache_status = JSON.parse(response)
339
+
340
+ log_header('Gathering files based on negotiation')
341
+
342
+ files = []
343
+ paths = []
344
+ file_paths.each do |file|
345
+ if cache_status[digest(file)]
346
+ #Server already knows about this file. No need to upload it.
347
+ files << digest(file)
348
+ else
349
+ #Upload file
350
+ files << File.new(file)
351
+ end
352
+
353
+ if file.start_with?(feature_prefix)
354
+ prefix = feature_prefix
355
+ else
356
+ prefix = workspace_prefix
357
+ end
358
+ paths << file.sub(prefix, '')
359
+ end
360
+
361
+ if config
362
+ files << File.new(config)
363
+ paths << 'config/cucumber.yml'
364
+ end
365
+
366
+ app_file = cache_status[digest(app)] ? digest(app) : File.new(app)
367
+
368
+ return app_file, files, paths
369
+ end
370
+
371
+ def digest(file)
372
+ Digest::SHA256.file(file).hexdigest
373
+ end
374
+
375
+ def unzip_file (file, destination)
376
+ Zip::ZipFile.open(file) { |zip_file|
377
+ zip_file.each { |f|
378
+ f_path=File.join(destination, f.name)
379
+ FileUtils.mkdir_p(File.dirname(f_path))
380
+ zip_file.extract(f, f_path) unless File.exist?(f_path)
381
+ }
382
+ }
383
+ end
384
+
385
+
386
+ def is_android?
387
+ app.end_with? '.apk'
388
+ end
389
+
390
+ def calabash_android_version
391
+ `bundle exec calabash-android version`.strip
392
+ end
393
+
394
+ def is_ios?
395
+ app.end_with? '.ipa'
396
+ end
397
+
398
+ def test_server_path
399
+ require 'digest/md5'
400
+ digest = Digest::MD5.file(app).hexdigest
401
+ File.join('test_servers', "#{digest}_#{calabash_android_version}.apk")
402
+ end
403
+
404
+ def all_files
405
+ dir = workspace
406
+ if features_zip
407
+ dir = Dir.mktmpdir
408
+ unzip_file(features_zip, dir)
409
+ dir = File.join(dir, File::Separator)
410
+ end
411
+
412
+
413
+ files = Dir.glob(File.join("#{dir}features", '**', '*'))
414
+
415
+ if File.directory?("#{dir}playback")
416
+ files += Dir.glob(File.join("#{dir}playback", '*'))
417
+ end
418
+
419
+ if config
420
+ files << config
421
+ end
422
+
423
+
424
+ files += Dir.glob(File.join("#{workspace}vendor", 'cache', '*'))
425
+
426
+ if workspace and workspace.strip != ''
427
+ files += Dir.glob("#{workspace}Gemfile")
428
+ files += Dir.glob("#{workspace}Gemfile.lock")
429
+ end
430
+
431
+ if is_android?
432
+ files << test_server_path
433
+ end
434
+
435
+ {:feature_prefix => dir, :workspace_prefix => workspace, :files => files.find_all { |file_or_dir| File.file? file_or_dir }}
436
+ end
437
+
438
+ def http_post(address, args, &block)
439
+ exec_options = {}
440
+ if ENV['XTC_USERNAME'] && ENV['XTC_PASSWORD']
441
+ exec_options[:user] = ENV['XTC_USERNAME']
442
+ exec_options[:password] = ENV['XTC_PASSWORD']
443
+ end
444
+
445
+ if block_given?
446
+ exec_options = exec_options.merge ({:method => :post, :url => "#{host}/#{address}", :payload => args,
447
+ :timeout => 90000000,
448
+ :open_timeout => 90000000,
449
+ :headers => {:content_type => 'multipart/form-data'}})
450
+ response = RestClient::Request.execute(exec_options) do |response, request, result, &other_block|
451
+ block.call(response, request, result, &other_block)
452
+ end
453
+ else
454
+ exec_options = exec_options.merge(:method => :post, :url => "#{host}/#{address}", :payload => args)
455
+ response = RestClient::Request.execute(exec_options)
456
+ end
457
+
458
+ response.body
459
+ end
460
+
461
+ def is_windows?
462
+ (RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/)
463
+ end
464
+
465
+ def is_macosx?
466
+ (RbConfig::CONFIG['host_os'] =~ /darwin/)
467
+ end
468
+
469
+ def validate_ipa(ipa)
470
+ result = false
471
+ dir = Dir.mktmpdir #do |dir|
472
+
473
+ unzip_file(ipa, dir)
474
+ unless File.directory?("#{dir}/Payload") #macos only
475
+ raise ValidationError, "Unzipping #{ipa} to #{dir} failed: Did not find a Payload directory (invalid .ipa)."
476
+ end
477
+ app_dir = Dir.foreach("#{dir}/Payload").find { |d| /\.app$/.match(d) }
478
+ app = app_dir.split('.')[0]
479
+ res = `otool "#{File.expand_path(dir)}/Payload/#{app_dir}/#{app}" -o 2> /dev/null | grep CalabashServer`
480
+
481
+ if /CalabashServer/.match(res)
482
+ puts "ipa: #{ipa} *contains* calabash.framework"
483
+ result = :calabash
484
+ end
485
+
486
+ unless result
487
+ res = `otool "#{File.expand_path(dir)}/Payload/#{app_dir}/#{app}" -o 2> /dev/null | grep FrankServer`
488
+ if /FrankServer/.match(res)
489
+ puts "ipa: #{ipa} *contains* FrankServer"
490
+ result = :frank
491
+ else
492
+ puts "ipa: #{ipa} *does not contain* calabash.framework"
493
+ result = false
494
+ end
495
+ end
496
+
497
+ result
498
+ end
499
+
500
+
501
+ def log(message)
502
+ puts "#{Time.now } #{message}"
503
+ $stdout.flush
504
+ end
505
+
506
+ def log_header(message)
507
+ if is_windows?
508
+ puts "\n### #{message} ###"
509
+ else
510
+ puts "\n\e[#{35}m### #{message} ###\e[0m"
511
+ end
512
+ end
513
+
514
+
515
+ def verify_app_and_extract_test_server
516
+ server = nil
517
+
518
+ unless File.exist?(app)
519
+ raise ValidationError, "No such file: #{app}"
520
+ end
521
+ unless (/\.(apk|ipa)$/ =~ app)
522
+ raise ValidationError, '<APP> should be either an ipa or apk file.'
523
+ end
524
+ if is_ios? and is_macosx? and not skip_check
525
+ log_header('Checking ipa for linking with Calabash')
526
+ server = validate_ipa(app)
527
+ abort_unless(server) do
528
+ puts 'The .ipa file does not seem to be linked with Calabash.'
529
+ puts 'Verify that your app is linked correctly.'
530
+ puts 'To disable this check run with --skip-check or set Environment Variable CHECK_IPA=0'
531
+ end
532
+ end
533
+ server
534
+ end
535
+
536
+ def abort(&block)
537
+ yield block
538
+ exit 1
539
+ end
540
+
541
+ def abort_unless(condition, &block)
542
+ unless condition
543
+ yield block
544
+ exit 1
545
+ end
546
+ end
547
+
548
+ def log_and_abort(message)
549
+ abort do
550
+ puts message
551
+ end
552
+ end
553
+
554
+
555
+ def verify_dependencies
556
+ if is_android?
557
+ abort_unless(File.exist?(test_server_path)) do
558
+ puts 'No test server found. Please run:'
559
+ puts " calabash-android build #{app}"
560
+ end
561
+
562
+ calabash_gem = Dir.glob('vendor/cache/calabash-android-*').first
563
+ abort_unless(calabash_gem) do
564
+ puts 'calabash-android was not packaged correct.'
565
+ puts 'Please tell testcloud@xamarin.com about this bug.'
566
+ end
567
+ end
568
+ end
569
+
570
+
571
+ def parse_and_set_config_and_profile
572
+ config_path = options[:config]
573
+ if config_path
574
+ config_path = File.expand_path(config_path)
575
+ unless File.exist?(config_path)
576
+ raise ValidationError, "Config file does not exist #{config_path}"
577
+ end
578
+
579
+
580
+ begin
581
+ config_yml = YAML.load_file(config_path)
582
+ rescue Exception => e
583
+ puts "Unable to parse #{config_path} as yml. Is this your Cucumber.yml file?"
584
+ raise ValidationError, e
585
+ end
586
+
587
+ if ENV['DEBUG']
588
+ puts 'Parsed Cucumber config as:'
589
+ puts config_yml.inspect
590
+ end
591
+
592
+ profile = options[:profile]
593
+ unless profile
594
+ raise ValidationError, 'Config file provided but no profile selected.'
595
+ else
596
+ unless config_yml[profile]
597
+ raise ValidationError, "Config file provided did not contain profile #{profile}."
598
+ else
599
+ puts "Using profile #{profile}..."
600
+ self.profile = profile
601
+ end
602
+ end
603
+ else
604
+ if options[:profile]
605
+ raise ValidationError, 'Profile selected but no config file provided.'
606
+ end
607
+ end
608
+
609
+ self.config = config_path
610
+ end
611
+
612
+ end
613
+
614
+
615
+ end
616
+ end
617
+
618
+
@@ -0,0 +1,3 @@
1
+ module XamarinTestCloud
2
+ VERSION = '0.9.1'
3
+ end
@@ -0,0 +1 @@
1
+ require 'calabash-cucumber/calabash_steps'
@@ -0,0 +1,4 @@
1
+ Given /^I am on the Welcome Screen$/ do
2
+ element_exists("view")
3
+ sleep(STEP_PAUSE)
4
+ end
@@ -0,0 +1 @@
1
+ require 'calabash-cucumber/cucumber'
File without changes
@@ -0,0 +1,77 @@
1
+ ########################################
2
+ # #
3
+ # Important Note #
4
+ # #
5
+ # When running calabash-ios tests at #
6
+ # www.xamarin-test-cloud.com #
7
+ # this file will be overwritten by #
8
+ # a file which automates #
9
+ # app launch on devices. #
10
+ # #
11
+ # Don't rely on this file being #
12
+ # present when running at #
13
+ # www.xamarin-test-cloud.com. #
14
+ # #
15
+ # Only put stuff here to automate #
16
+ # iOS Simulator. #
17
+ # #
18
+ # You can put your app bundle path #
19
+ # for automating simulator app start: #
20
+ # Uncomment APP_BUNDLE_PATH =.. #
21
+ # #
22
+ ########################################
23
+
24
+ require 'calabash-cucumber/launch/simulator_helper'
25
+ require 'sim_launcher'
26
+
27
+ # Uncomment and replace ?? appropriately
28
+ # This should point to your Simulator build
29
+ # which includes calabash framework
30
+ # this is usually the Calabash build configuration
31
+ # of your production target.
32
+ #APP_BUNDLE_PATH = "~/Library/Developer/Xcode/DerivedData/??/Build/Products/Calabash-iphonesimulator/??.app"
33
+ #
34
+
35
+ def reset_app_jail(sdk, app_path)
36
+ app = File.basename(app_path)
37
+ bundle = `find "#{ENV['HOME']}/Library/Application Support/iPhone Simulator/#{sdk}/Applications/" -type d -depth 2 -name #{app} | head -n 1`
38
+ return if bundle.empty? # Assuming we're already clean
39
+
40
+ sandbox = File.dirname(bundle)
41
+ ['Library', 'Documents', 'tmp'].each do |dir|
42
+ FileUtils.rm_rf(File.join(sandbox, dir))
43
+ end
44
+ end
45
+
46
+ def relaunch
47
+ if ENV['NO_LAUNCH']!="1"
48
+ sdk = ENV['SDK_VERSION'] || SimLauncher::SdkDetector.new().latest_sdk_version
49
+ path = Calabash::Cucumber::SimulatorHelper.app_bundle_or_raise(app_path)
50
+ if ENV['RESET_BETWEEN_SCENARIOS']=="1"
51
+ reset_app_jail(sdk, path)
52
+ end
53
+
54
+ Calabash::Cucumber::SimulatorHelper.relaunch(path,sdk,ENV['DEVICE'] || 'iphone')
55
+ end
56
+ end
57
+
58
+ def app_path
59
+ ENV['APP_BUNDLE_PATH'] || (defined?(APP_BUNDLE_PATH) && APP_BUNDLE_PATH)
60
+ end
61
+
62
+ def calabash_notify
63
+ if self.respond_to?(:on_launch)
64
+ self.on_launch
65
+ end
66
+ end
67
+
68
+ Before do |scenario|
69
+ relaunch
70
+ calabash_notify
71
+ end
72
+
73
+ at_exit do
74
+ if ENV['NO_LAUNCH']!="1" and ENV['NO_STOP']!="1"
75
+ Calabash::Cucumber::SimulatorHelper.stop
76
+ end
77
+ end
@@ -0,0 +1,62 @@
1
+ require 'test/unit'
2
+ require 'thor'
3
+ require 'fileutils'
4
+ require 'xamarin-test-cloud/cli'
5
+
6
+ class TestParser < Test::Unit::TestCase
7
+ def test_should_raise_if_no_app_or_api_key_is_given
8
+ script = XamarinTestCloud::CLI.new([])
9
+ assert_raise Thor::InvocationError do
10
+ script.invoke(:submit)
11
+ end
12
+
13
+ script = XamarinTestCloud::CLI.new(["test/ipa/2012 Olympics_cal.ipa"])
14
+ assert_raise Thor::InvocationError do
15
+ script.invoke(:submit)
16
+ end
17
+
18
+
19
+ end
20
+
21
+ def test_should_raise_if_app_is_not_file_ipa_or_apk
22
+ script = XamarinTestCloud::CLI.new(["test/ipa/NONE_EXIST_2012 Olympics_cal.ipa","JIFZCTPZJJXJLEKMMYRY","."])
23
+ assert_raise RuntimeError do
24
+ script.invoke(:submit)
25
+ end
26
+
27
+ script = XamarinTestCloud::CLI.new(["test/ipa/features.zip","JIFZCTPZJJXJLEKMMYRY","."])
28
+
29
+ assert_raise RuntimeError do
30
+ script.invoke(:submit)
31
+ end
32
+ end
33
+
34
+ def test_should_parse_all_configuration_options
35
+ FileUtils.rm_f(File.join("test","vendor"))
36
+ FileUtils.rm_f(File.join("test","Gemfile"))
37
+ FileUtils.rm_f(File.join("test","Gemfile.lock"))
38
+
39
+ config_options = {
40
+ :host => "http://localhost:8080",
41
+ :workspace => "test",
42
+ :features => "test/ipa/features.zip",
43
+ :config => "test/config/cucumber.yml",
44
+ :profile => "a",
45
+ "skip-check" => false,
46
+ "reset-between-scenarios" => false,
47
+ "dry-run" => true
48
+ }
49
+ script = XamarinTestCloud::CLI.new(["test/ipa/2012 Olympics_cal.ipa","JIFZCTPZJJXJLEKMMYRY"],config_options)
50
+
51
+
52
+ script.invoke(:submit)
53
+
54
+ FileUtils.rm_f(File.join("test","vendor","cache"))
55
+ FileUtils.rm_f(File.join("test","Gemfile"))
56
+ FileUtils.rm_f(File.join("test","Gemfile.lock"))
57
+
58
+
59
+
60
+ end
61
+
62
+ end
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xamarin-test-cloud
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.1
5
+ platform: ruby
6
+ authors:
7
+ - Karl Krukow
8
+ - Jonas Maturana Larsen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-07-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thor
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '>='
19
+ - !ruby/object:Gem::Version
20
+ version: 0.18.1
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '>='
26
+ - !ruby/object:Gem::Version
27
+ version: 0.18.1
28
+ - !ruby/object:Gem::Dependency
29
+ name: bundler
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - '>='
33
+ - !ruby/object:Gem::Version
34
+ version: 1.3.0
35
+ - - <
36
+ - !ruby/object:Gem::Version
37
+ version: '2.0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - '>='
43
+ - !ruby/object:Gem::Version
44
+ version: 1.3.0
45
+ - - <
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ - !ruby/object:Gem::Dependency
49
+ name: json
50
+ requirement: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rubyzip
64
+ requirement: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 0.9.9
69
+ type: :runtime
70
+ prerelease: false
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: 0.9.9
76
+ - !ruby/object:Gem::Dependency
77
+ name: rest-client
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: 1.6.7
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: 1.6.7
90
+ description: Xamarin Test Cloud let's you automatically test your app on hundreds
91
+ of mobile devices
92
+ email:
93
+ - karl@xamarin.com
94
+ - jonas@xamarin.com
95
+ executables:
96
+ - test-cloud
97
+ extensions: []
98
+ extra_rdoc_files: []
99
+ files:
100
+ - bin/test-cloud
101
+ - lib/GemfileAndroid
102
+ - lib/GemfileIOS
103
+ - lib/xamarin-test-cloud/cli.rb
104
+ - lib/xamarin-test-cloud/version.rb
105
+ - README.md
106
+ - CHANGES.txt
107
+ - test/ipa/features/step_definitions/calabash_steps.rb
108
+ - test/ipa/features/step_definitions/my_first_steps.rb
109
+ - test/ipa/features/support/env.rb
110
+ - test/ipa/features/support/hooks.rb
111
+ - test/ipa/features/support/launch.rb
112
+ - test/test_parser.rb
113
+ homepage: http://xamarin.com/test-cloud
114
+ licenses: []
115
+ metadata: {}
116
+ post_install_message:
117
+ rdoc_options: []
118
+ require_paths:
119
+ - lib
120
+ required_ruby_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ required_rubygems_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ requirements: []
131
+ rubyforge_project:
132
+ rubygems_version: 2.0.5
133
+ signing_key:
134
+ specification_version: 4
135
+ summary: Command-line interface to Xamarin Test Cloud
136
+ test_files:
137
+ - test/ipa/features/step_definitions/calabash_steps.rb
138
+ - test/ipa/features/step_definitions/my_first_steps.rb
139
+ - test/ipa/features/support/env.rb
140
+ - test/ipa/features/support/hooks.rb
141
+ - test/ipa/features/support/launch.rb
142
+ - test/test_parser.rb