123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- require 'rails_helper'
- RSpec.describe Package, type: :model do
- # cleanup package files
- after :all do # rubocop:disable RSpec/BeforeAfterAll
- %w[example.rb app/controllers/test_controller.rb].each do |file|
- next if !Rails.root.join(file).exist?
- Rails.root.join(file).delete
- end
- end
- def get_package_structure(name, files, version = '1.0.1')
- <<-JSON
- {
- "name": "#{name}",
- "version": "#{version}",
- "vendor": "Zammad Foundation",
- "license": "ABC",
- "url": "https://zammad.org/",
- "description": [
- {
- "language": "en",
- "text": "some description"
- }
- ],
- "files": #{files}
- }
- JSON
- end
- let(:package_zpm_files_json) do
- <<-JSON
- [
- {
- "permission": "644",
- "location": "example.rb",
- "content": "YWJjw6TDtsO8w58="
- },
- {
- "permission": "644",
- "location": "app/controllers/test_controller.rb",
- "content": "YWJjw6TDtsO8w58="
- }
- ]
- JSON
- end
- let(:package_name) { 'UnitTestSample' }
- let(:package_zpm_json) { get_package_structure(package_name, package_zpm_files_json) }
- let(:old_package_zpm_json) { get_package_structure(package_name, package_zpm_files_json, '1.0.0') }
- let(:new_package_zpm_json) { get_package_structure(package_name, package_zpm_files_json, '1.0.2') }
- context 'when performing different package actions' do
- context 'when installing a package' do
- it 'does install package' do
- expect { described_class.install(string: package_zpm_json) }
- .to change(described_class, :count)
- .and change(Store, :count)
- end
- end
- context 'when reinstalling a package' do
- before do
- described_class.install(string: package_zpm_json)
- end
- it 'does not reinstall package' do
- expect { described_class.reinstall(package_name) }
- .to not_change(described_class, :count)
- .and not_change(Store, :count)
- end
- end
- context 'when installing a package again' do
- before do
- described_class.install(string: package_zpm_json)
- end
- it 'does not install package' do
- expect { described_class.install(string: package_zpm_json) }
- .to raise_error(RuntimeError)
- .and not_change(described_class, :count)
- .and not_change(Store, :count)
- end
- end
- context 'when installing a package with a lower version' do
- before do
- described_class.install(string: package_zpm_json)
- end
- it 'does not install package' do
- expect { described_class.install(string: old_package_zpm_json) }
- .to raise_error(RuntimeError)
- .and not_change(described_class, :count)
- .and not_change(Store, :count)
- end
- end
- context 'when upgrading a package' do
- before do
- described_class.install(string: package_zpm_json)
- end
- it 'does install package' do
- expect { described_class.install(string: new_package_zpm_json) }
- .to not_raise_error
- .and not_change(described_class, :count)
- .and change(Store, :count)
- end
- end
- context 'when installing + uninstalling a package' do
- before do
- described_class.install(string: package_zpm_json)
- end
- it 'does install + uninstall the package' do
- expect { described_class.uninstall(string: package_zpm_json) }
- .to not_raise_error
- .and change(described_class, :count)
- .and not_change(Store, :count)
- end
- end
- context 'when auto installing' do
- before do
- FileUtils.mkdir_p(Rails.root.join('auto_install'))
- location = Rails.root.join('auto_install/unittest.zpm')
- file = File.new(location, 'wb')
- file.write(package_zpm_json)
- file.close
- end
- after do
- Rails.root.join('auto_install/unittest.zpm').delete
- end
- it 'does install package' do
- expect { described_class.auto_install }
- .to change(described_class, :count)
- .and change(Store, :count)
- end
- end
- context 'when verify package install' do
- context 'when verify is ok' do
- it 'returns no verify issues' do
- package = described_class.install(string: package_zpm_json)
- expect(package.verify).to be_nil
- end
- end
- context 'when verify is not ok' do
- it 'returns verify issues' do
- package = described_class.install(string: package_zpm_json)
- Rails.root.join('example.rb').delete
- expect(package.verify).not_to be_nil
- end
- end
- end
- end
- context 'with different file locations' do
- context 'with correct file locations' do
- it 'installation should work' do
- expect(described_class.install(string: package_zpm_json)).to be_truthy
- end
- end
- shared_examples 'check not allowed file location' do |file_location|
- let(:package_zpm_files_json) do
- <<-JSON
- [
- {
- "permission": "644",
- "location": "example.rb",
- "content": "YWJjw6TDtsO8w58="
- },
- {
- "permission": "644",
- "location": "#{file_location}",
- "content": "YWJjw6TDtsO8w58="
- }
- ]
- JSON
- end
- it 'installation should raise a error and package/store should not be present, because of not allowed file location' do
- expect { described_class.install(string: package_zpm_json) }
- .to raise_error(RuntimeError)
- .and not_change(described_class, :count)
- .and not_change(Store, :count)
- end
- end
- context "with not allowed file location part: '..'" do
- include_examples 'check not allowed file location', '../../../../../tmp/test_controller.rb'
- end
- context "with not allowed file location part: '%2e%2e'" do
- include_examples 'check not allowed file location', '%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/tmp/test_controller.rb'
- end
- end
- describe 'Multiple uninstalling packages will course missing backup files #4577' do
- let(:core_file) { Rails.root.join('app/models/ticket.rb') }
- let(:orig_content) { File.read(core_file) }
- let(:package_zpm_files_json) do
- <<-JSON
- [
- {
- "permission": "644",
- "location": "app/models/ticket.rb",
- "content": "YWJjw6TDtsO8w58="
- }
- ]
- JSON
- end
- before do
- orig_content
- end
- def expect_install_package
- described_class.install(string: package_zpm_json)
- expect(File.exist?(core_file)).to be(true)
- expect(File.read(core_file)).to eq('abcäöüß')
- expect(File.exist?("#{core_file}.save")).to be(true)
- expect(File.read("#{core_file}.save")).to eq(orig_content)
- expect(described_class.last.state).to eq('installed')
- end
- def expect_uninstall_package_files
- described_class.uninstall(string: package_zpm_json, migration_not_down: true, reinstall: true)
- expect(File.exist?(core_file)).to be(true)
- expect(File.read(core_file)).to eq(orig_content)
- expect(File.exist?("#{core_file}.save")).to be(false)
- expect(described_class.last.state).to eq('uninstalled')
- end
- def expect_reinstall_package
- described_class.reinstall(package_name)
- expect(File.exist?(core_file)).to be(true)
- expect(File.read(core_file)).to eq('abcäöüß')
- expect(File.exist?("#{core_file}.save")).to be(true)
- expect(File.read("#{core_file}.save")).to eq(orig_content)
- expect(described_class.last.state).to eq('installed')
- end
- def expect_uninstall_package
- described_class.uninstall(string: package_zpm_json)
- expect(File.exist?(core_file)).to be(true)
- expect(File.read(core_file)).to eq(orig_content)
- expect(File.exist?("#{core_file}.save")).to be(false)
- expect(File.read(core_file)).to eq(orig_content)
- end
- it 'does support the classic package migration path but with multiple uninstalls' do
- expect_install_package
- expect_uninstall_package_files
- expect_uninstall_package_files
- expect_reinstall_package
- expect_uninstall_package
- end
- it 'does have a proper package state after multiple reinstalls' do
- expect_install_package
- expect_reinstall_package
- expect_reinstall_package
- expect_uninstall_package
- end
- end
- describe 'Vendor url in installed package is the zammad instance url #4753' do
- it 'does have a url for the package' do
- described_class.install(string: package_zpm_json)
- expect(described_class.last.url).to eq('https://zammad.org/')
- end
- end
- describe 'Package: Missing backup files for files with the same content #5012' do
- let(:package_v1_files) do
- <<-JSON
- [
- {
- "permission": "644",
- "location": "lib/version.rb",
- "content": "#{Base64.strict_encode64(File.read('lib/version.rb')).strip}"
- }
- ]
- JSON
- end
- let(:package_v2_files) do
- <<-JSON
- []
- JSON
- end
- let(:package_v1) { get_package_structure(package_name, package_v1_files, '1.0.0') }
- let(:package_v2) { get_package_structure(package_name, package_v2_files, '1.0.1') }
- it 'does not lose core files when patched by package and released in future updates of zammad' do
- described_class.install(string: package_v1)
- described_class.install(string: package_v2)
- expect(File.exist?('lib/version.rb')).to be(true)
- end
- end
- describe 'Package: File conflict with packages which include the same file location #5014' do
- let(:package_1) { get_package_structure('PackageA', package_zpm_files_json, '1.0.0') }
- let(:package_2) { get_package_structure('PackageB', package_zpm_files_json, '1.0.0') }
- it 'does not allow to patch the same file twice via package' do
- described_class.install(string: package_1)
- expect { described_class.install(string: package_2) }.to raise_error("Can't create file, because file 'example.rb' is already provided by package 'PackageA'!")
- end
- end
- end
|