diff options
Diffstat (limited to 'mmc_updater/src/tests/test-update.rb')
-rwxr-xr-x | mmc_updater/src/tests/test-update.rb | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/mmc_updater/src/tests/test-update.rb b/mmc_updater/src/tests/test-update.rb new file mode 100755 index 00000000..82965cf4 --- /dev/null +++ b/mmc_updater/src/tests/test-update.rb @@ -0,0 +1,218 @@ +#!/usr/bin/ruby + +require 'fileutils.rb' +require 'find' +require 'rbconfig' +require 'optparse' + +# Install directory - this contains a space to check +# for correct escaping of paths when passing comamnd +# line arguments under Windows +INSTALL_DIR = File.expand_path("install dir/") +PACKAGE_DIR = File.expand_path("package-dir/") +PACKAGE_SRC_DIR = File.expand_path("package-src-dir/") +IS_WINDOWS = RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ + +if IS_WINDOWS + OLDAPP_NAME = "oldapp.exe" + NEWAPP_NAME = "newapp.exe" + APP_NAME = "app.exe" + UPDATER_NAME = "updater.exe" + ZIP_TOOL = File.expand_path("../zip-tool.exe") +else + OLDAPP_NAME = "oldapp" + NEWAPP_NAME = "newapp" + APP_NAME = "app" + UPDATER_NAME = "updater" + ZIP_TOOL = File.expand_path("../zip-tool") +end + +file_list_vars = { + "APP_FILENAME" => APP_NAME, + "UPDATER_FILENAME" => UPDATER_NAME +} + +def replace_vars(src_file,dest_file,vars) + content = File.read(src_file) + vars.each do |key,value| + content.gsub! "$#{key}",value + end + File.open(dest_file,'w') do |file| + file.print content + end +end + +# Returns true if |src_file| and |dest_file| have the same contents, type +# and permissions or false otherwise +def compare_files(src_file, dest_file) + if File.ftype(src_file) != File.ftype(dest_file) + $stderr.puts "Type of file #{src_file} and #{dest_file} differ" + return false + end + + if File.file?(src_file) && !FileUtils.identical?(src_file, dest_file) + $stderr.puts "Contents of file #{src_file} and #{dest_file} differ" + return false + end + + src_stat = File.stat(src_file) + dest_stat = File.stat(dest_file) + + if src_stat.mode != dest_stat.mode + $stderr.puts "Permissions of #{src_file} and #{dest_file} differ" + return false + end + + return true +end + +# Compares the contents of two directories and returns a map of (file path => change type) +# for files and directories which differ between the two +def compare_dirs(src_dir, dest_dir) + src_dir += '/' if !src_dir.end_with?('/') + dest_dir += '/' if !dest_dir.end_with?('/') + + src_file_map = {} + Find.find(src_dir) do |src_file| + src_file = src_file[src_dir.length..-1] + src_file_map[src_file] = nil + end + + change_map = {} + Find.find(dest_dir) do |dest_file| + dest_file = dest_file[dest_dir.length..-1] + + if !src_file_map.include?(dest_file) + change_map[dest_file] = :deleted + elsif !compare_files("#{src_dir}/#{dest_file}", "#{dest_dir}/#{dest_file}") + change_map[dest_file] = :updated + end + + src_file_map.delete(dest_file) + end + + src_file_map.each do |file| + change_map[file] = :added + end + + return change_map +end + +def create_test_file(name, content) + File.open(name, 'w') do |file| + file.puts content + end + return name +end + +force_elevation = false +run_in_debugger = false + +OptionParser.new do |parser| + parser.on("-f","--force-elevated","Force the updater to elevate itself") do + force_elevation = true + end + parser.on("-d","--debug","Run the updater under GDB") do + run_in_debugger = true + end +end.parse! + +# copy 'src' to 'dest', preserving the attributes +# of 'src' +def copy_file(src, dest) + FileUtils.cp src, dest, :preserve => true +end + +# Remove the install and package dirs if they +# already exist +FileUtils.rm_rf(INSTALL_DIR) +FileUtils.rm_rf(PACKAGE_DIR) +FileUtils.rm_rf(PACKAGE_SRC_DIR) + +# Create the install directory with the old app +Dir.mkdir(INSTALL_DIR) +copy_file OLDAPP_NAME, "#{INSTALL_DIR}/#{APP_NAME}" + +# Create a dummy file to uninstall +uninstall_test_file = create_test_file("#{INSTALL_DIR}/file-to-uninstall.txt", "this file should be removed after the update") +uninstall_test_symlink = if not IS_WINDOWS + FileUtils.ln_s("#{INSTALL_DIR}/file-to-uninstall.txt", "#{INSTALL_DIR}/symlink-to-file-to-uninstall.txt") +else + create_test_file("#{INSTALL_DIR}/symlink-to-file-to-uninstall.txt", "dummy file. this is a symlink on Unix") +end + +# Populate package source dir with files to install +Dir.mkdir(PACKAGE_SRC_DIR) +nested_dir_path = "#{PACKAGE_SRC_DIR}/new-dir/new-dir2" +FileUtils.mkdir_p(nested_dir_path) +FileUtils::chmod 0755, "#{PACKAGE_SRC_DIR}/new-dir" +FileUtils::chmod 0755, "#{PACKAGE_SRC_DIR}/new-dir/new-dir2" +nested_dir_test_file = "#{nested_dir_path}/new-file.txt" +File.open(nested_dir_test_file,'w') do |file| + file.puts "this is a new file in a new nested dir" +end +FileUtils::chmod 0644, nested_dir_test_file +copy_file NEWAPP_NAME, "#{PACKAGE_SRC_DIR}/#{APP_NAME}" +FileUtils::chmod 0755, "#{PACKAGE_SRC_DIR}/#{APP_NAME}" + +# Create .zip packages from source files +Dir.mkdir(PACKAGE_DIR) +Dir.chdir(PACKAGE_SRC_DIR) do + if !system("#{ZIP_TOOL} #{PACKAGE_DIR}/app-pkg.zip .") + raise "Unable to create update package" + end +end + +# Copy the install script and updater to the target +# directory +replace_vars("file_list.xml","#{PACKAGE_DIR}/file_list.xml",file_list_vars) +copy_file "../#{UPDATER_NAME}", "#{PACKAGE_DIR}/#{UPDATER_NAME}" + +# Run the updater using the new syntax +# +# Run the application from the install directory to +# make sure that it looks in the correct directory for +# the file_list.xml file and packages +# +install_path = File.expand_path(INSTALL_DIR) +Dir.chdir(INSTALL_DIR) do + flags = "--force-elevated" if force_elevation + debug_flags = "gdb --args" if run_in_debugger + cmd = "#{debug_flags} #{PACKAGE_DIR}/#{UPDATER_NAME} #{flags} --install-dir \"#{install_path}\" --package-dir \"#{PACKAGE_DIR}\" --script file_list.xml --auto-close" + puts "Running '#{cmd}'" + system(cmd) +end + +# TODO - Correctly wait until updater has finished +sleep(1) + +# Check that the app was updated +app_path = "#{INSTALL_DIR}/#{APP_NAME}" +output = `"#{app_path}"` +if (output.strip != "new app starting") + throw "Updated app produced unexpected output: #{output}" +end + +# Check that the packaged dir and install dir match +dir_diff = compare_dirs(PACKAGE_SRC_DIR, INSTALL_DIR) +ignored_files = ["test-dir", "test-dir/app-symlink", UPDATER_NAME] +have_unexpected_change = false +dir_diff.each do |path, change_type| + if !ignored_files.include?(path) + case change_type + when :added + $stderr.puts "File #{path} was not installed" + when :changed + $stderr.puts "File #{path} differs between install and package dir" + when :deleted + $stderr.puts "File #{path} was not uninstalled" + end + have_unexpected_change = true + end +end + +if have_unexpected_change + throw "Unexpected differences between packaging and update dir" +end + +puts "Test passed" |