从CircleCi 2.0迁移后失败的规范

我已经通过Ruby on Rails项目进行迁移,以在CircleCi 2.0上运行testing。 这样做后,一些与file upload相关的规格失败。 我有以下型号:

SlideAudio:

class SlideAudio < ApplicationRecord # == Extensions ============================================================ Paperclip.interpolates :locale do |attachment, style| attachment.instance.locale end # Tell paperclip that :slide_id means SlideAudio#slide_id # This is used in the custom path and url below when we define the attachment Paperclip.interpolates :slide_id do |attachment, style| attachment.instance.slide_id end has_attached_file :audio, path: ":rails_root/public/slides/:attachment/:style/:locale/:slide_id.:extension", url: "/slides/:attachment/:style/:locale/:slide_id.:extension", processors: [:audio_compression], styles: { original: {}, compressed_96k: {bitrate: '96k'} } # == Associations ========================================================== belongs_to :slide, optional: true # == Validations =========================================================== validates_attachment :audio, content_type: { content_type: [ 'audio/mpeg', 'audio/x-mpeg', 'audio/mp3', 'audio/x-mp3', 'audio/mpeg3', 'audio/x-mpeg3', 'audio/mpg', 'audio/x-mpg', 'audio/x-mpegaudio' ] } # == Instance Methods ====================================================== def has_a_valid_audio_file? return false if audio.blank? # Before a slide_audio is saved, the audio file lives in the tmp directory. if audio.queued_for_write.present? && audio.queued_for_write[:original].present? temporary_path = audio.queued_for_write[:original].path File.exists?(temporary_path) # After a slide is saved, Paperclip copies that file to "path". elsif audio.path.present? File.exists?(audio.path) else false end end end 

滑动:

 class Slide < ApplicationRecord has_many :audios, class_name: 'SlideAudio' end 

我也有class级负责压缩audio:

 module Paperclip class AudioCompression < Processor def make original_filepath = @file.path if should_skip_compression? # If no compression is needed, we can't just return the original file (@file) # because Paperclip will remove it during cleanup. # That's why we need to copy it and return that copy. new_filepath = original_filepath.gsub('.mp3', '-copy.mp3') FileUtils.cp(original_filepath, new_filepath) return File.open(new_filepath) end desired_bitrate = options[:bitrate] # This is formatted as a string that ffmpeg accepts, eg "96k" Paperclip::AudioCompression.compress(original_filepath, desired_bitrate) end protected # This method is not required by Paperclip processors - it is our "helper" method. # If the original bitrate is not significantly higher than the desired bitrate, # we won't try to compress, because we would lose sound quality and wouldn't gain much. def should_skip_compression? return true if options[:style] == :original # Do not compress original files. desired_bitrate = options[:bitrate] # This is formatted as a string that ffmpeg accepts, eg "96k" desired_bitrate_in_kbs = desired_bitrate.to_i # This is a number, eg 96. original_audio_info = `ffmpeg -i #{@file.path} 2>&1` original_bitrate = original_audio_info.match(/(?:bitrate: )(\d+) (?:kb\/s)$/)&.captures&.first original_bitrate_in_kbs = original_bitrate.to_i upper_acceptable_bitrate_limit_in_kbs = desired_bitrate_in_kbs + 5 original_bitrate_in_kbs < upper_acceptable_bitrate_limit_in_kbs end def self.compress(original_filepath, desired_bitrate) # This file doesn't exist yet, we're just constructing the filepath. compressed_filepath = original_filepath.gsub('.mp3', "-#{desired_bitrate}.mp3") # Use ffmpeg to compress the original file. # The files are usually uploaded to a temporary location, such as /var/folders. # The flags used: # -y: If there's a temporary file at compressed_filepath, overwrite it. # -i: Specifies the input filepath. # -ab: Specifies the desired bitrate. Paperclip.run('ffmpeg', "-y -i #{original_filepath} -ab #{desired_bitrate} #{compressed_filepath}") File.open(compressed_filepath) end end end 

我的testing看起来像这样:

 require 'rails_helper' RSpec.describe SlideAudio, type: :model do describe 'Instance Methods' do let(:slide) { create(:slide) } let(:audio) { slide.audios.create(locale: 'en') } let(:audio_file_128k) do Rack::Test::UploadedFile.new( 'spec/fixtures/audios/test-128k.mp3', 'audio/mpeg') end let(:audio_file_96k) do Rack::Test::UploadedFile.new( 'spec/fixtures/audios/test-96k.mp3', 'audio/mpeg') end describe '#audio=' do it 'should compress mp3 files to 96 kbps if their bitrate is too high' do audio.audio = audio_file_128k audio.save! audio_info = `ffmpeg -i #{audio.audio.path(:compressed_96k)} 2>&1` bitrate_info = audio_info[/bitrate:.*$/] expect(bitrate_info).to eq('bitrate: 96 kb/s') end end end end 

并且正在失败,输出如下:

  Failure/Error: expect(bitrate_info).to eq('bitrate: 96 kb/s') expected: "bitrate: 96 kb/s" got: nil (compared using ==) 

任何想法如何解决这个问题? 这是我的circle.yml文件:

 version: 2 environment: TZ: "/usr/share/zoneinfo/America/Los_Angeles" jobs: build: parallelism: 2 working_directory: ~/circleci-survey-builder docker: - image: circleci/ruby:2.3.4 environment: PGHOST: 127.0.0.1 PGUSER: ubuntu RAILS_ENV: test - image: circleci/postgres:9.6-alpine environment: POSTGRES_USER: ubuntu POSTGRES_DB: circle_test POSTGRES_PASSWORD: '' steps: - checkout - run: name: 'Install CircleCI dependencies' command: bash deploy/circle-dependencies.sh - type: cache-restore key: survey-builder-{{ checksum "Gemfile.lock" }} - run: name: 'Install dependencies' command: bundle install --path vendor/bundle - type: cache-save key: survey-builder-{{ checksum "Gemfile.lock" }} paths: - vendor/bundle - run: name: 'Create database.yml' command: mv config/database.ci.yml config/database.yml - run: name: Set up SurveyBuilder database command: bundle exec rake db:structure:load --trace - run: name: Set up Dashboard database command: | createdb dashboard_test psql -p 5432 dashboard_test < db/dashboard_test.sql - run: name: Set up foreign data wrapper command: psql -p 5432 circle_test < db/test_foreign_data_wrapper.sql - run: name: 'Run tests' command: | bundle exec rspec --format progress \ $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)