Rails RSpec 第二个 ssh 请求的 net-ssh mock return
Rails RSpec net-ssh mock return of second ssh request
我正在开发一个经常访问远程服务器上的模拟数据的 Web 应用程序。我想为这些请求期间可能发生的错误处理创建测试。
我目前遇到的问题是我似乎无法使用 ssh_with_stderr
方法模拟请求。 ssh
方法工作正常。
这是我要测试的代码:
# app/jobs/zip_files_sync_job.rb
class ZipFilesSyncJob < ApplicationJob
queue_as :default
discard_on ActiveJob::DeserializationError
def perform(simulation)
simulation.zip_files.each do |f|
if f.path.nil? && f.created_at < 6.hours.ago
f.state = 'error'
f.save!
next
end
next if f.path.nil?
_, errors = simulation.server.ssh_with_stderr("ls #{f.path.shellescape}")
if errors.blank?
f.size = f.simulation.server.ssh("stat -c %s #{f.path.shellescape}")
f.state = 'ready' if f.size.to_i.positive?
elsif f.state == 'ready' && errors.present?
f.state = 'error'
elsif f.state == 'zipping' && errors.present? && f.created_at < 6.hours.ago
f.state = 'error'
end
f.save!
end
end
end
这就是我要测试的内容:
# spec/jobs/zip_files_sync_job_spec.rb
require 'rails_helper'
RSpec.describe ZipFilesSyncJob, type: :job do
let(:private_group) { Group::PRIVATE }
let(:user) { FactoryBot.create :user }
let(:server) { FactoryBot.create :server, user: user, external_storage: false }
let(:simulation) { FactoryBot.create :simulation, user: user, group: private_group, server: server }
let(:zip_file) { FactoryBot.create :zip_file, simulation: simulation, path: 'test/zip_file', state: 'pending', size: '100' }
let(:zip_file_no_path) { FactoryBot.create :zip_file, simulation: simulation, path: nil, created_at: 10.hours.ago, state: 'pending' }
let(:ssh_connection) { double('net-ssh') }
before do
zip_file_no_path
allow(Net::SSH).to receive(:start).and_yield(ssh_connection)
end
def perform_zip_file_sync(zip_file)
perform_enqueued_jobs do
ZipFilesSyncJob.perform_now(simulation)
end
zip_file.reload
yield
allow(Net::SSH).to receive(:start).and_call_original
end
describe '#perform' do
include ActiveJob::TestHelper
#################################
##### This test works fine #####
#################################
context 'with no errors' do
before do
zip_file
end
it 'it will change the state to ready' do
allow(Net::SSH).to receive(:start).and_return('144371201')
perform_zip_file_sync(zip_file) do
expect(zip_file.state).to eq 'ready'
end
end
end
#############################################################################
##### This test fails because it does not return on the ssh_with_stderr #####
#############################################################################
context 'with errors' do
it 'will change the state to error' do
allow(Net::SSH).to receive(:start).and_return("[' ', 'Error with connection']")
perform_enqueued_jobs do
ZipFilesSyncJob.perform_now(simulation)
end
zip_file.reload
expect(zip_file.state).to eq 'error'
end
end
end
end
这是服务器连接的代码。它使用 net-ssh
gem
# app/models/server.rb
Class Server < ApplicationRecord
def ssh(command, storage = true, &block)
Net::SSH.start(hostname, username, port: port, keys: ["key"], non_interactive: true, timeout: 1) do |ssh|
ssh.exec! "cd #{folder.shellescape}; #{command}", &block
end
end
def ssh_with_stderr(command)
@output = ""
@errors = ""
begin
Net::SSH.start(hostname, username, port: port, keys: ["key"], non_interactive: true, timeout: 1) do |ssh|
ssh.exec! "cd #{folder.shellescape}; #{command}" do |_ch, stream, data|
if stream == :stderr
@errors += data
else
@output += data
end
end
end
rescue Net::SSH::Exception, Errno::ECONNREFUSED, Errno::EINVAL, Errno::EADDRNOTAVAIL => e
@output = nil
@errors = e.message
end
[@output, @errors]
end
有了这个模拟
allow(Net::SSH).to receive(:start).and_return("[' ', 'Error with connection']")
ssh_with_stderr
看起来像
def ssh_with_stderr(command)
@output = ""
@errors = ""
begin
[' ', 'Error with connection']
rescue Net::SSH::Exception, Errno::ECONNREFUSED, Errno::EINVAL, Errno::EADDRNOTAVAIL => e
@output = nil
@errors = e.message
end
[@output, @errors]
end
所以它总是 returns ["",""]
,并且检查 errors.blank?
总是积极的。
尝试用 and_raise
而不是 and_return
模拟 Net::SSH
,比如
allow(Net::SSH).to receive(:start).and_raise(Errno::ECONNREFUSED, "Error with connection")
我正在开发一个经常访问远程服务器上的模拟数据的 Web 应用程序。我想为这些请求期间可能发生的错误处理创建测试。
我目前遇到的问题是我似乎无法使用 ssh_with_stderr
方法模拟请求。 ssh
方法工作正常。
这是我要测试的代码:
# app/jobs/zip_files_sync_job.rb
class ZipFilesSyncJob < ApplicationJob
queue_as :default
discard_on ActiveJob::DeserializationError
def perform(simulation)
simulation.zip_files.each do |f|
if f.path.nil? && f.created_at < 6.hours.ago
f.state = 'error'
f.save!
next
end
next if f.path.nil?
_, errors = simulation.server.ssh_with_stderr("ls #{f.path.shellescape}")
if errors.blank?
f.size = f.simulation.server.ssh("stat -c %s #{f.path.shellescape}")
f.state = 'ready' if f.size.to_i.positive?
elsif f.state == 'ready' && errors.present?
f.state = 'error'
elsif f.state == 'zipping' && errors.present? && f.created_at < 6.hours.ago
f.state = 'error'
end
f.save!
end
end
end
这就是我要测试的内容:
# spec/jobs/zip_files_sync_job_spec.rb
require 'rails_helper'
RSpec.describe ZipFilesSyncJob, type: :job do
let(:private_group) { Group::PRIVATE }
let(:user) { FactoryBot.create :user }
let(:server) { FactoryBot.create :server, user: user, external_storage: false }
let(:simulation) { FactoryBot.create :simulation, user: user, group: private_group, server: server }
let(:zip_file) { FactoryBot.create :zip_file, simulation: simulation, path: 'test/zip_file', state: 'pending', size: '100' }
let(:zip_file_no_path) { FactoryBot.create :zip_file, simulation: simulation, path: nil, created_at: 10.hours.ago, state: 'pending' }
let(:ssh_connection) { double('net-ssh') }
before do
zip_file_no_path
allow(Net::SSH).to receive(:start).and_yield(ssh_connection)
end
def perform_zip_file_sync(zip_file)
perform_enqueued_jobs do
ZipFilesSyncJob.perform_now(simulation)
end
zip_file.reload
yield
allow(Net::SSH).to receive(:start).and_call_original
end
describe '#perform' do
include ActiveJob::TestHelper
#################################
##### This test works fine #####
#################################
context 'with no errors' do
before do
zip_file
end
it 'it will change the state to ready' do
allow(Net::SSH).to receive(:start).and_return('144371201')
perform_zip_file_sync(zip_file) do
expect(zip_file.state).to eq 'ready'
end
end
end
#############################################################################
##### This test fails because it does not return on the ssh_with_stderr #####
#############################################################################
context 'with errors' do
it 'will change the state to error' do
allow(Net::SSH).to receive(:start).and_return("[' ', 'Error with connection']")
perform_enqueued_jobs do
ZipFilesSyncJob.perform_now(simulation)
end
zip_file.reload
expect(zip_file.state).to eq 'error'
end
end
end
end
这是服务器连接的代码。它使用 net-ssh
gem
# app/models/server.rb
Class Server < ApplicationRecord
def ssh(command, storage = true, &block)
Net::SSH.start(hostname, username, port: port, keys: ["key"], non_interactive: true, timeout: 1) do |ssh|
ssh.exec! "cd #{folder.shellescape}; #{command}", &block
end
end
def ssh_with_stderr(command)
@output = ""
@errors = ""
begin
Net::SSH.start(hostname, username, port: port, keys: ["key"], non_interactive: true, timeout: 1) do |ssh|
ssh.exec! "cd #{folder.shellescape}; #{command}" do |_ch, stream, data|
if stream == :stderr
@errors += data
else
@output += data
end
end
end
rescue Net::SSH::Exception, Errno::ECONNREFUSED, Errno::EINVAL, Errno::EADDRNOTAVAIL => e
@output = nil
@errors = e.message
end
[@output, @errors]
end
有了这个模拟
allow(Net::SSH).to receive(:start).and_return("[' ', 'Error with connection']")
ssh_with_stderr
看起来像
def ssh_with_stderr(command)
@output = ""
@errors = ""
begin
[' ', 'Error with connection']
rescue Net::SSH::Exception, Errno::ECONNREFUSED, Errno::EINVAL, Errno::EADDRNOTAVAIL => e
@output = nil
@errors = e.message
end
[@output, @errors]
end
所以它总是 returns ["",""]
,并且检查 errors.blank?
总是积极的。
尝试用 and_raise
而不是 and_return
模拟 Net::SSH
,比如
allow(Net::SSH).to receive(:start).and_raise(Errno::ECONNREFUSED, "Error with connection")