lib = File.dirname(File.dirname(__FILE__)) + '/lib'
$:.unshift(lib) unless $:.include?(lib)
require 'rubygems'
gem "minitest"
require 'minitest/autorun'
require 'fileutils'
require 'yaml'
require 'ruboto/sdk_versions'
require 'ruboto/sdk_locations'
require 'ruboto/util/update'
module RubotoTest
include Ruboto::SdkVersions
include Ruboto::SdkLocations
include Ruboto::Util::Update
PROJECT_DIR = File.expand_path('..', File.dirname(__FILE__))
$LOAD_PATH << PROJECT_DIR
unless ENV['GEM_HOME'] && File.writable?(ENV['GEM_HOME'])
GEM_PATH = File.join PROJECT_DIR, 'tmp', 'gems'
FileUtils.mkdir_p GEM_PATH
ENV['GEM_HOME'] = GEM_PATH
ENV['GEM_PATH'] = GEM_PATH
ENV['PATH'] = "#{GEM_PATH}/bin:#{ENV['PATH']}"
Gem.paths = GEM_PATH
Gem.refresh
end
`gem query -i -n bundler`
system 'gem install bundler --no-ri --no-rdoc' unless $? == 0
`bundle check`
system 'bundle --system' unless $? == 0
lib_path = File.expand_path('lib', File.dirname(File.dirname(__FILE__)))
$LOAD_PATH.unshift lib_path unless $LOAD_PATH.include?(lib_path)
require 'ruboto'
require 'ruboto/version'
PACKAGE = 'org.ruboto.test_app'
APP_NAME = 'RubotoTestApp'
TMP_DIR = File.join PROJECT_DIR, 'tmp'
APP_DIR = File.join TMP_DIR, APP_NAME
# FIXME(uwe): Remove special case when Android L has been released.
if (ENV['ANDROID_TARGET'] && ENV['ANDROID_TARGET'] =~ /(?:android-)?L/)
ANDROID_TARGET = 'L'
else
ANDROID_TARGET = (ENV['ANDROID_TARGET'] && ENV['ANDROID_TARGET'].slice(/\d+/).to_i) || MINIMUM_SUPPORTED_SDK_LEVEL
end
# EMXIF
def self.version_from_device
puts 'Reading OS version from device/emulator'
system 'adb wait-for-device'
IO.popen('adb bugreport').each_line do |line|
if line =~ /sdk-eng (.*?) .*? .*? test-keys/
version = $1
api_level = VERSION_TO_API_LEVEL[version]
raise "Unknown version: #{version}" if api_level.nil?
return "android-#{api_level}"
end
if line =~ /\[ro\.build\.version\.sdk\]: \[(\d+)\]/
return $1
end
end
raise 'Unable to read device/emulator apilevel'
end
def uninstall_jruby_jars_gem
uninstall_ruboto_gem
uninstall_gem('jruby-jars')
end
def uninstall_ruboto_gem
uninstall_gem('ruboto')
end
def uninstall_gem(name)
`gem query --no-installed -n #{name}`
system "gem uninstall -x --all #{name}" if $? != 0
assert_equal 0, $?, "uninstall of #{name} failed with return code #$?"
end
def install_ruboto_gem(version)
version_requirement = "-v #{version}"
`gem query -i -n ^ruboto$ #{version_requirement}`
system "gem install ruboto #{version_requirement} --no-ri --no-rdoc" unless $? == 0
raise "install of ruboto #{version} failed with return code #$?" unless $? == 0
end
# FIXME(uwe): Remove when stupid crash is resolved
def has_stupid_crash
require 'rbconfig'
ANDROID_OS <= 15 &&
JRUBY_JARS_VERSION >= Gem::Version.new('1.7.19') &&
RbConfig::CONFIG['host_os'].downcase.include?('linux')
end
# EMXIF
puts RUBY_DESCRIPTION
ANDROID_OS = (ENV['ANDROID_OS'] || version_from_device).slice(/\d+/).to_i
# FIXME(uwe): Remove when Android L has been released
ANDROID_OS = 21 if ANDROID_OS == 0
# EMXIF
puts "ANDROID_OS: #{ANDROID_OS}"
puts "ANDROID_TARGET: #{ANDROID_TARGET}"
RUBOTO_CMD = "ruby -rubygems -I #{PROJECT_DIR}/lib #{PROJECT_DIR}/bin/ruboto"
puts "ANDROID_HOME: #{ANDROID_HOME}"
puts "ANDROID_SDK_TOOLS_REVISION: #{ANDROID_TOOLS_REVISION}"
RUBOTO_PLATFORM = ENV['RUBOTO_PLATFORM'] || 'CURRENT'
puts "RUBOTO_PLATFORM: #{RUBOTO_PLATFORM}"
if RUBOTO_PLATFORM == 'CURRENT'
JRUBY_JARS_VERSION = Gem::Version.new('1.7.19')
elsif ENV['JRUBY_JARS_VERSION']
JRUBY_JARS_VERSION = Gem::Version.new(ENV['JRUBY_JARS_VERSION'])
else
# FIXME(uwe): Simplify when we stop supporting rubygems < 1.8.0
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.8.0')
gem_spec = Gem::Specification.find_by_path 'jruby-jars'
else
gem_spec = Gem.searcher.find('jruby-jars')
end
# EMXIF
raise StandardError.new("Can't find Gem specification jruby-jars.") unless gem_spec
JRUBY_JARS_VERSION = gem_spec.version
end
puts "JRUBY_JARS_VERSION: #{JRUBY_JARS_VERSION}"
ENV['JRUBY_JARS_VERSION'] = JRUBY_JARS_VERSION.to_s
ENV['LOCAL_GEM_DIR'] = Dir.getwd
end
class Minitest::Test
include RubotoTest
extend RubotoTest
alias old_run run
def run(*args, &block)
mark_test_start("#{self.class.name}\##{name}")
result = old_run(*args, &block)
mark_test_end("#{self.class.name}\##{name}")
result
end
def mark_test_start(test_name)
@start_time = Time.now
log
log '=' * 80
log "Starting test #{test_name} at #{@start_time.strftime('%Y-%m-%d %H:%M:%S')}:"
log
end
def mark_test_end(test_name)
log
duration = (Time.now - @start_time).to_i
log "Ended test #{test_name}: #{passed? ? 'PASSED' : 'FAILED'} after #{duration / 60}:#{'%02d' % (duration % 60)}"
log '=' * 80
log
end
def log(message = '')
puts message
`adb shell log -t 'RUBOTO TEST' '#{message}'`
end
def generate_app(options = {})
bundle = options.delete(:bundle)
example = options.delete(:example) || false
# FIXME(uwe): Remove exclusion feature
excluded_stdlibs = options.delete(:excluded_stdlibs)
# EMXIF
heap_alloc = options.delete(:heap_alloc)
included_stdlibs = options.delete(:included_stdlibs)
package = options.delete(:package) || PACKAGE
standalone = options.delete(:standalone) || !!included_stdlibs || !!excluded_stdlibs || ENV['RUBOTO_PLATFORM'] == 'STANDALONE'
update = options.delete(:update) || false
ruby_version = options.delete(:ruby_version) || (JRUBY_JARS_VERSION.to_s[0..0] == '9' ? '2.2' : '1.9')
raise "Unknown options: #{options.inspect}" unless options.empty?
raise 'Inclusion/exclusion of libs requires standalone mode.' if (included_stdlibs || excluded_stdlibs) && !standalone
Dir.mkdir TMP_DIR unless File.exists? TMP_DIR
FileUtils.rm_rf APP_DIR if File.exists? APP_DIR
template_dir = "#{APP_DIR}_template_#{$$}"
template_dir << "_package_#{package}" if package != PACKAGE
template_dir << "_heap_alloc_#{heap_alloc}" if heap_alloc
# template_dir << "_ruby_version_#{ruby_version.to_s.gsub('.', '_')}" if ruby_version
template_dir << "_example_#{example}" if example
template_dir << "_bundle_#{[*bundle].map(&:to_s).join('_').gsub(/[{}\[\]'",:=~<>\/ ]+/, '_')}" if bundle
template_dir << '_updated' if update
template_dir << '_standalone' if standalone
template_dir << "_without_#{excluded_stdlibs.map { |ed| ed.gsub(/[.\/]/, '_') }.join('_')}" if excluded_stdlibs
template_dir << "_with_#{included_stdlibs.map { |ed| ed.gsub(/[.\/]/, '_') }.join('_')}" if included_stdlibs
if File.exists?(template_dir)
puts "Copying app from template #{template_dir}"
FileUtils.cp_r template_dir, APP_DIR, :preserve => true
else
if example
Dir.chdir TMP_DIR do
system "tar xzf #{PROJECT_DIR}/examples/#{APP_NAME}_#{example}.tgz"
Dir.chdir(APP_NAME) { system '../../bin/ruboto setup -y' }
end
Dir.chdir APP_DIR do
File.open('local.properties', 'w') { |f| f.puts "sdk.dir=#{ANDROID_HOME}" }
File.open('test/local.properties', 'w') { |f| f.puts "sdk.dir=#{ANDROID_HOME}" }
if standalone
if included_stdlibs || excluded_stdlibs || heap_alloc
write_ruboto_yml(included_stdlibs, excluded_stdlibs, heap_alloc, ruby_version)
end
FileUtils.touch 'libs/jruby-core-x.x.x.jar'
FileUtils.touch 'libs/jruby-stdlib-x.x.x.jar'
install_jruby_jars_gem
else
FileUtils.rm(Dir['libs/{jruby-*.jar,dx.jar}'])
end
end
else
if standalone
install_jruby_jars_gem
else
uninstall_jruby_jars_gem
end
puts "Generating app #{APP_DIR}"
system "#{RUBOTO_CMD} gen app --package #{package} --path #{APP_DIR} --name #{APP_NAME} --target android-#{ANDROID_TARGET}"
if $? != 0
FileUtils.rm_rf APP_DIR
raise "gen app failed with return code #$?"
end
Dir.chdir APP_DIR do
write_gemfile(bundle) if bundle
if included_stdlibs || excluded_stdlibs || heap_alloc
sleep 1
write_ruboto_yml(included_stdlibs, excluded_stdlibs, heap_alloc, ruby_version)
system 'rake build_xml jruby_adapter'
end
if standalone
system "#{RUBOTO_CMD} gen jruby #{JRUBY_JARS_VERSION}"
raise "update jruby failed with return code #$?" if $? != 0
end
end
end
Dir.chdir APP_DIR do
write_android_manifest
File.write('res/layout/dummy_layout.xml', <<-EOF)
EOF
if update
update_app
end
if update || !example
system 'rake --trace debug' # Ensure dx heap space is sufficient.
assert_equal 0, $?
end
end
puts "Storing app as template #{template_dir}"
FileUtils.cp_r APP_DIR, template_dir, :preserve => true
end
end
def update_app
system "#{RUBOTO_CMD} update app -t #{ANDROID_TARGET} #{"--with-jruby #{JRUBY_JARS_VERSION}" if RUBOTO_PLATFORM == 'STANDALONE'}"
assert_equal 0, $?, "update app failed with return code #$?"
end
def cleanup_app
# FileUtils.rm_rf APP_DIR if File.exists? APP_DIR
end
def run_app_tests
check_platform_installation
test_completed = false
Thread.start do
4.times do
sleep 600
break if test_completed
puts '...'
end
end
Dir.chdir APP_DIR do
system 'rake --trace test:quick'
assert_equal 0, $?, "tests failed with return code #$?"
end
test_completed = true
end
def check_platform_installation
if RUBOTO_PLATFORM == 'STANDALONE'
system 'rake platform:uninstall'
elsif RUBOTO_PLATFORM == 'CURRENT'
system 'rake platform:current'
elsif RUBOTO_PLATFORM == 'FROM_GEM'
system 'rake platform:install'
else
fail "Unknown Ruboto platform: #{RUBOTO_PLATFORM.inspect}"
end
if $? != 0
FileUtils.rm_rf 'tmp/RubotoCore'
fail 'Error (un)installing RubotoCore'
end
end
def write_ruboto_yml(included_stdlibs, excluded_stdlibs, heap_alloc, ruby_version)
options = {}
options['included_stdlibs'] = included_stdlibs if included_stdlibs
options['excluded_stdlibs'] = excluded_stdlibs if excluded_stdlibs
options['ruby_version'] = ruby_version if ruby_version
options['heap_alloc'] = heap_alloc if heap_alloc
yml = YAML.dump(options)
puts "Adding ruboto.yml:\n#{yml}"
File.open('ruboto.yml', 'w') { |f| f << yml }
end
def write_gemfile(bundle)
gems = [*bundle].map { |g| g.is_a?(Symbol) ? g.to_s : g }
puts "Adding Gemfile.apk: #{gems.join(' ')}"
File.open('Gemfile.apk', 'w') do |f|
f << "source 'http://rubygems.org/'\n\n"
gems.each { |g| f << "gem #{[*g].map { |gp| (gp.is_a?(Symbol) ? gp.to_s : gp).inspect }.join(', ')}\n" }
end
end
def write_project_properties(api_level)
puts "Write project.properties with api level #{api_level}"
properties_file = 'project.properties'
properties = File.read(properties_file)
properties.sub!(/^target=android-\d+/, "target=android-#{api_level}")
File.write(properties_file, properties)
end
def write_android_manifest
File.write('AndroidManifest.xml',
File.read('AndroidManifest.xml').sub(%r{},
" \n"))
end
end