convertr 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -44,6 +44,7 @@ rescue LoadError
44
44
  end
45
45
  end
46
46
 
47
+ task :rcov => ['convertr:prepare_test']
47
48
  task :test => [:check_dependencies, 'convertr:prepare_test']
48
49
 
49
50
  task :default => :test
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.2
1
+ 0.1.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{convertr}
8
- s.version = "0.0.2"
8
+ s.version = "0.1.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Ilya Lityuga", "Alexander Svetkin"]
12
- s.date = %q{2010-10-13}
12
+ s.date = %q{2010-10-14}
13
13
  s.default_executable = %q{convertr}
14
14
  s.description = %q{Convertr works with database and handles converting tasks. It fetches files from remote sources and converts them to appropriate formats with ffmpeg}
15
15
  s.email = %q{ilya.lityuga@gmail.com}
@@ -21,7 +21,7 @@ module Convertr
21
21
  CONVERTOR_PAUSE_DELAY = 120
22
22
  CONVERTOR_MAX_FETCH_TIME = 600
23
23
 
24
- attr_accessor :scheduler, :max_tasks, :hostname, :initial_dir, :file, :task, :file_path, :work_path, :tasks
24
+ attr_accessor :scheduler, :max_tasks, :hostname, :initial_dir, :file, :task, :tasks, :logger
25
25
 
26
26
  def initialize(max_tasks = 0, scheduler = nil) # инициализация конертера {{{
27
27
  @max_tasks = max_tasks
@@ -37,11 +37,11 @@ module Convertr
37
37
  loop do
38
38
  break if File.exists? CONVERTOR_STOPFILE
39
39
  if !File.exists?(CONVERTOR_PAUSEFILE) and @task = @scheduler.schedule_next_task(@hostname)
40
- task.update_attributes(
40
+ @task.update_attributes(
41
41
  :convert_status => process_task,
42
42
  :convert_stopped_at => Time.now
43
43
  )
44
- break if @max_tasks > 0 && (@tasks += 1) > @max_tasks
44
+ break if @max_tasks > 0 && (@tasks += 1) >= @max_tasks
45
45
  else
46
46
  sleep(CONVERTOR_PAUSE_DELAY) && next
47
47
  end
@@ -52,19 +52,17 @@ module Convertr
52
52
 
53
53
  def process_task # выполнение конкретной задачи на конвертацию {{{
54
54
  @file = @task.file
55
- @file_path = File.join(@conf.tmp_dir, @file.name)
56
- @working_dir = File.join( File.dirname(@file_path), File.filename(@filepath) )
57
- @logger.info("Started #@filepath")
55
+ @logger.info("Started #{original_file}")
58
56
  begin
59
- fetch_file(@file.source_location, @file.name)
60
- FileUtils.cd @working_dir
57
+ fetch_file(@file.location, @file.filename)
58
+ FileUtils.cd indir
61
59
  process_profile(profile_by_bitrate(@task.bitrate))
62
60
  if @task.bitrate == 600
63
61
  count = calc_thumbnails_count(@file.duration)
64
62
  interval = (@file.duration / count).to_i
65
- system(make_thumbnails_cmd(count, interval, 150, 0, 2)) or raise "thumbnails generation failed #{$?}"
63
+ system(make_thumbnails_cmd(count, interval, 150, nil, 2)) or raise "thumbnails generation failed #{$?}"
66
64
  end
67
- @logger.info("Done #@filepath")
65
+ @logger.info("Done #{original_file}")
68
66
  rescue StandardError => e
69
67
  @logger.error e.message
70
68
  return 'FAILURE'
@@ -75,13 +73,12 @@ module Convertr
75
73
  end # }}}
76
74
 
77
75
  def fetch_file(source_url, filename) # скачивание файла по FTP {{{
78
- FileUtils.mkpath(@working_dir)
79
- dst_file = File.join(@working_dir, File.basename(filename))
80
- tmp_file = dst_file + ".part"
76
+ FileUtils.mkpath(indir)
77
+ tmp_file = work_name + ".part"
81
78
  started_at = Time.now
82
79
  loop do
83
- return if File.exists? dst_file
84
- if File.exists? tmp_file
80
+ return if ::File.exists? original_file
81
+ if ::File.exists? tmp_file
85
82
  sleep(CONVERTOR_PAUSE_DELAY)
86
83
  if Time.now > started_at + CONVERTOR_MAX_FETCH_TIME
87
84
  FileUtils.rm_f tmp_file
@@ -94,18 +91,17 @@ module Convertr
94
91
  end
95
92
 
96
93
  url = URI.parse(source_url)
97
- begin
98
- ftp = Net::Ftp.open(url.host)
99
- ftp.login(@conf.ftp_user, @conf.ftp_pass)
100
- ftp.getbinaryfile(url.path, tmp_file, 1024)
101
- rescue StandardError => e
102
- ftp.close
103
- FileUtils.rm_f tmp_file
104
- raise e
94
+ Net::FTP.open(url.host) do |ftp|
95
+ begin
96
+ ftp.login(@conf.ftp_user, @conf.ftp_pass)
97
+ ftp.getbinaryfile(url.path, tmp_file, 1024)
98
+ rescue StandardError => e
99
+ FileUtils.rm_f tmp_file
100
+ raise e
101
+ end
105
102
  end
106
- ftp.close
107
103
 
108
- FileUtils.rename tmp_file, dst_file
104
+ FileUtils.move tmp_file, original_file
109
105
  end # }}}
110
106
 
111
107
  def profile_by_bitrate(bitrate) # bitrate -> profile {{{
@@ -120,37 +116,35 @@ module Convertr
120
116
 
121
117
  def process_profile(pname) # конвертация, согласно профилю # {{{
122
118
  profile = @conf.enc_profiles[pname]
123
- outfile = File.join(@working_dir, File.filename(@file.name), "-#{pname}-0.mp4")
124
- infile = File.join(@working_dir, File.basename(@file.name))
125
- output_dir = File.join(@conf.output_dir, @working_dir)
126
- FileUtils.mkpath output_dir unless File.exists? output_dir
127
- FileUtils.chdir output_dir
128
- FileUtils.mkdir pname unless File.exists? pname
129
- FileUtils.chdir pname
119
+ outfile = filename_with_suffix("-#{pname}-0.mp4") # => z-sd-0.mp4
120
+ FileUtils.mkdir(pname) && FileUtils.chdir(pname)
130
121
 
131
122
  @conf.enc_pass.each_with_index do |enc_pass_params, i|
132
- cmd = mkcmd(enc_pass_params, pname, infile, i == 0 ? '/dev/null' : outfile, @file.aspect)
123
+ cmd = mkcmd(enc_pass_params, pname, original_file, i == 0 ? '/dev/null' : outfile, @file.aspect)
133
124
  @logger.info(cmd)
134
125
  system(cmd) or raise "system #{cmd} failed: #{$?}"
135
126
  end
136
127
 
137
- outfile2 = File.join(@working_dir, File.filename(@file.name), "-#{pname}.mp4")
138
- cmd = "#{@conv.qtfaststart} #{outfile} #{outfile2}"
128
+ outfile2 = filename_with_suffix("-#{pname}.mp4") # => z-sd.mp4
129
+ cmd = "#{@conf.qtfaststart} #{outfile} #{outfile2}"
139
130
  system(cmd) or FileUtils.rm_f(outfile) && raise("system #{cmd} failed: #{$?}")
131
+ FileUtils.rm_f(outfile)
132
+ FileUtils.mkpath outdir # => /var/x/y
133
+ FileUtils.move outfile2, outdir
140
134
  FileUtils.cd '..'
141
135
  FileUtils.rm_rf pname
142
136
  end # }}}
143
137
 
144
138
  def make_thumbnails_cmd(count, interval, w, h, postfix) # генерация тумбнейлов {{{
145
- w = (h * @file.float_aspect).to_i if h && w.nil?
146
- h = (w / @file.float_aspect).to_i if @file.aspect && w && h.nil?
139
+ file = task.file
140
+ w = (h * file.float_aspect).to_i if h && w.nil?
141
+ h = (w / file.float_aspect).to_i if file.aspect && w && h.nil?
147
142
  tstamps = (1..count).collect {|i| i * interval}
148
143
  params = ''
149
- params += ' -c 20 ' if @task.crop?
150
- params += ' -d ' if @task.deinterlace?
151
- output_dir = File.join(@conf.output_dir, @working_dir)
152
- pattern = File.join(@working_dir, File.filename(@file.name), "-%d-#{postfix}.jpg")
153
- "#{@conf.tmaker} -i #{infile} #{params} -w #{w} -h #{h} -o #{output_dir} #{tstamps.join(' ')}"
144
+ params += ' -c 20 ' if task.crop?
145
+ params += ' -d ' if task.deinterlace?
146
+ pattern = filename_with_suffix("-%d-#{postfix}.jpg")
147
+ "#{@conf.tmaker} -i #{original_file} #{params} -w #{w} -h #{h} -o \"#{outdir}/#{pattern}\" #{tstamps.join(' ')}"
154
148
  end # }}}
155
149
 
156
150
  def mkcmd(enc_pass, pname, infile, outfile, aspect) # подготовка команды на конвертацию {{{
@@ -173,10 +167,10 @@ module Convertr
173
167
  (params['croptop'], params['cropbottom'], params['cropleft'], params['cropright']) =
174
168
  case aspect
175
169
  when '16:9'
176
- w += 32 && h += 18
170
+ w += 32 ; h += 18
177
171
  [10, 8, 16, 16]
178
172
  else # '4:3', '5:3' etc
179
- w += 32 && h += 24
173
+ w += 32 ; h += 24
180
174
  [20, 4, 16, 16]
181
175
  end
182
176
  end
@@ -195,5 +189,31 @@ module Convertr
195
189
  else 24
196
190
  end
197
191
  end # }}}
192
+
193
+ # тут чёрт ногу сломит с этими картами директорий
194
+ # /tmp/test.avi
195
+ def original_file
196
+ ::File.join(@conf.tmp_dir, ::File.basename(@file.filename))
197
+ end
198
+
199
+ # /tmp/test
200
+ def indir
201
+ ::File.join(@conf.tmp_dir, ::File.filename(@file.filename))
202
+ end
203
+
204
+ # /tmp/test/test
205
+ def work_name
206
+ ::File.join(@conf.tmp_dir, ::File.filename(@file.filename), ::File.filename(@file.filename))
207
+ end
208
+
209
+ # test + suffix
210
+ def filename_with_suffix(suffix)
211
+ ::File.filename(@file.filename) + suffix
212
+ end
213
+
214
+ # /var/x/y
215
+ def outdir
216
+ ::File.join(@conf.output_dir, ::File.dirname(@file.filename))
217
+ end
198
218
  end
199
219
  end
@@ -20,11 +20,11 @@ module Convertr
20
20
  t.integer :file_id
21
21
  t.integer :bitrate
22
22
  t.string :convert_status, :limit => 20
23
- t.boolean :convert_started
24
- t.boolean :convert_stopped
23
+ t.datetime :convert_started_at
24
+ t.datetime :convert_stopped_at
25
25
  t.string :copy_status, :limit => 20
26
- t.boolean :copy_started
27
- t.boolean :copy_stopped
26
+ t.datetime :copy_started_at
27
+ t.datetime :copy_stopped_at
28
28
  t.boolean :crop
29
29
  t.boolean :deinterlace
30
30
  end
@@ -21,7 +21,7 @@ module Convertr
21
21
  def schedule(task, convertor)
22
22
  Convertr::Task.transaction do
23
23
  task.update_attributes(:convert_status => 'PROGRESS', :convert_started_at => Time.now)
24
- task.file.update_attribute(:convertor => convertor)
24
+ task.file.update_attribute(:convertor, convertor)
25
25
  end
26
26
  end
27
27
  end
@@ -2,8 +2,8 @@ module Convertr
2
2
  module Scheduler
3
3
  class AllBtFirst < Base
4
4
  def get_task_for_schedule(convertor)
5
- Convertr::Task.for_convertor(convertor).first# ||
6
- # Convertr::File.without_convertor.select {|f| !f.tasks.empty?}.tasks.first
5
+ Convertr::Task.for_convertor(convertor).first ||
6
+ Convertr::Task.without_convertor.first
7
7
  end
8
8
  end
9
9
  end
@@ -6,5 +6,6 @@ module Convertr
6
6
  scope :for_convertor, lambda { |convertor|
7
7
  not_completed.includes(:file).where('files.convertor' => convertor).order('files.broadcast_at asc')
8
8
  }
9
+ scope :without_convertor, not_completed.includes(:file).where('files.convertor is null').order('files.broadcast_at asc')
9
10
  end
10
11
  end
@@ -4,7 +4,7 @@ with_convertor1_1:
4
4
  location: /tmp
5
5
  enqueue_at: <%= Time.now %>
6
6
  convertor: convertor1
7
- broadcast_at: <%= Time.now - 3600 * 24 %>
7
+ broadcast_at: <%= Time.now - 3600 * 24 * 2 %>
8
8
  src_size: 12345
9
9
  duration: 12345
10
10
  aspect: 3x4
@@ -33,6 +33,7 @@ development: &non_production_settings
33
33
  ar: 44100
34
34
  ffmpeg: /usr/bin/ffmpeg
35
35
  tmaker: /usr/local/bin/tmaker
36
+ output_dir: /tmp/output
36
37
 
37
38
  test:
38
39
  <<: *non_production_settings
@@ -6,13 +6,18 @@ class TestConvertor < Test::Unit::TestCase
6
6
  @convertor = Convertr::Convertor.new
7
7
  end
8
8
 
9
- should "be able to calculate thumbnails count" do
10
- assert_equal 3, @convertor.instance_eval("calc_thumbnails_count(600)")
11
- assert_equal 6, @convertor.instance_eval("calc_thumbnails_count(1200)")
12
- assert_equal 9, @convertor.instance_eval("calc_thumbnails_count(1800)")
9
+ should "be able to calculate thumbnails count" do # {{{
10
+ assert_equal 3, @convertor.instance_eval { calc_thumbnails_count(600) }
11
+ assert_equal 6, @convertor.instance_eval { calc_thumbnails_count(1200) }
12
+ assert_equal 9, @convertor.instance_eval { calc_thumbnails_count(1800) }
13
+ assert_equal 12, @convertor.instance_eval { calc_thumbnails_count(2400) }
14
+ assert_equal 15, @convertor.instance_eval { calc_thumbnails_count(3000) }
15
+ assert_equal 18, @convertor.instance_eval { calc_thumbnails_count(3600) }
16
+ assert_equal 21, @convertor.instance_eval { calc_thumbnails_count(3700) }
17
+ assert_equal 24, @convertor.instance_eval { calc_thumbnails_count(4260) }
13
18
  end
14
-
15
- should "find the right profile by bitrate" do
19
+ # }}}
20
+ should "find the right profile by bitrate" do # {{{
16
21
  assert_equal 'sd', @convertor.instance_eval("profile_by_bitrate(300)")
17
22
  assert_equal 'hd', @convertor.instance_eval("profile_by_bitrate(600)")
18
23
  assert_equal 'hdp', @convertor.instance_eval("profile_by_bitrate(1000)")
@@ -20,14 +25,14 @@ class TestConvertor < Test::Unit::TestCase
20
25
  @convertor.instance_eval("profile_by_bitrate(1234)")
21
26
  end
22
27
  end
23
-
24
- context "for some task with crop and deinterlace" do
28
+ # }}}
29
+ context "for some task with crop and deinterlace" do # should prepare valid shell command for ffmpeg {{{
25
30
  setup do
26
31
  task = Factory.create(:task, :bitrate => 600, :crop => true, :deinterlace => true)
27
32
  @convertor.stubs(:task).returns(task)
28
33
  end
29
34
  should "prepare valid command for ffmpeg" do
30
- assert_equal '/usr/bin/ffmpeg -y -i infile.avi -s 1118x414 -ab 64k -ac 1 -acodec libfaac -ar 44100 -b 236k -bt 236k -cropbottom 8 -cropleft 16 -cropright 16 -croptop 10 -deinterlace -pass 2 -threads 3 -vcodec libx264 -vpre hq-flash outfile.mpg',
35
+ assert_equal '/usr/bin/ffmpeg -y -i infile.avi -s 736x414 -ab 64k -ac 1 -acodec libfaac -ar 44100 -b 236k -bt 236k -cropbottom 8 -cropleft 16 -cropright 16 -croptop 10 -deinterlace -pass 2 -threads 3 -vcodec libx264 -vpre hq-flash outfile.mpg',
31
36
  @convertor.instance_eval { mkcmd({'vpre' => 'hq-flash', 'pass' => 2}, 'sd', 'infile.avi', 'outfile.mpg', '16:9') }
32
37
  end
33
38
  end
@@ -38,7 +43,7 @@ class TestConvertor < Test::Unit::TestCase
38
43
  @convertor.stubs(:task).returns(task)
39
44
  end
40
45
  should "prepare valid command for ffmpeg" do
41
- assert_equal '/usr/bin/ffmpeg -y -i infile.avi -s 1118x414 -ab 64k -ac 1 -acodec libfaac -ar 44100 -b 236k -bt 236k -cropbottom 8 -cropleft 16 -cropright 16 -croptop 10 -pass 2 -threads 3 -vcodec libx264 -vpre hq-flash outfile.mpg',
46
+ assert_equal '/usr/bin/ffmpeg -y -i infile.avi -s 736x414 -ab 64k -ac 1 -acodec libfaac -ar 44100 -b 236k -bt 236k -cropbottom 8 -cropleft 16 -cropright 16 -croptop 10 -pass 2 -threads 3 -vcodec libx264 -vpre hq-flash outfile.mpg',
42
47
  @convertor.instance_eval { mkcmd({'vpre' => 'hq-flash', 'pass' => 2}, 'sd', 'infile.avi', 'outfile.mpg', '16:9') }
43
48
  end
44
49
  end
@@ -49,9 +54,164 @@ class TestConvertor < Test::Unit::TestCase
49
54
  @convertor.stubs(:task).returns(task)
50
55
  end
51
56
  should "prepare valid command for ffmpeg" do
52
- assert_equal '/usr/bin/ffmpeg -y -i infile.avi -s 704x396 -ab 64k -ac 1 -acodec libfaac -ar 44100 -b 236k -bt 236k -pass 2 -threads 3 -vcodec libx264 -vpre hq-flash outfile.mpg',
53
- @convertor.instance_eval { mkcmd({'vpre' => 'hq-flash', 'pass' => 2}, 'sd', 'infile.avi', 'outfile.mpg', '16:9') }
57
+ assert_equal '/usr/bin/ffmpeg -y -i infile.avi -s 640x480 -ab 64k -ac 1 -acodec libfaac -ar 44100 -b 236k -bt 236k -pass 2 -threads 3 -vcodec libx264 -vpre hq-flash outfile.mpg',
58
+ @convertor.instance_eval { mkcmd({'vpre' => 'hq-flash', 'pass' => 2}, 'sd', 'infile.avi', 'outfile.mpg', '4:3') }
59
+ end
60
+ end
61
+
62
+ context "for some task with unusual aspect (15:9) with crop" do
63
+ setup do
64
+ task = Factory.create(:task, :bitrate => 600, :crop => true, :deinterlace => false)
65
+ @convertor.stubs(:task).returns(task)
66
+ end
67
+ should "prepare valid command for ffmpeg" do
68
+ assert_equal '/usr/bin/ffmpeg -y -i infile.avi -s 672x408 -ab 64k -ac 1 -acodec libfaac -ar 44100 -b 236k -bt 236k -cropbottom 4 -cropleft 16 -cropright 16 -croptop 20 -pass 2 -threads 3 -vcodec libx264 -vpre hq-flash outfile.mpg',
69
+ @convertor.instance_eval { mkcmd({'vpre' => 'hq-flash', 'pass' => 2}, 'sd', 'infile.avi', 'outfile.mpg', '15:9') }
70
+ end
71
+ end
72
+
73
+ context "for some task with very unusual aspect (3:3)" do
74
+ setup do
75
+ task = Factory.create(:task, :bitrate => 600, :crop => false, :deinterlace => false)
76
+ @convertor.stubs(:task).returns(task)
77
+ end
78
+ should "prepare valid command for ffmpeg" do
79
+ assert_equal '/usr/bin/ffmpeg -y -i infile.avi -s 640x480 -ab 64k -ac 1 -acodec libfaac -ar 44100 -aspect 1.33333333 -b 236k -bt 236k -pass 2 -threads 3 -vcodec libx264 -vpre hq-flash outfile.mpg',
80
+ @convertor.instance_eval { mkcmd({'vpre' => 'hq-flash', 'pass' => 2}, 'sd', 'infile.avi', 'outfile.mpg', '3:3') }
81
+ end
82
+ end
83
+ #}}}
84
+ context "for task with crop and deinterlace and file with aspect 4:3" do # {{{
85
+ setup do
86
+ @convertor.file = Factory(:file, :aspect => '4:3', :filename => 'x/y/test.avi')
87
+ @convertor.task = Factory(:task, :file => @convertor.file, :crop => true, :deinterlace => true)
54
88
  end
89
+ should "prepare valid shell command for thumbnail generation" do # {{{
90
+ assert_equal "/usr/local/bin/tmaker -i /tmp/test.avi -c 20 -d -w 150 -h 112 -o \"/tmp/output/x/y/test-%d-2.jpg\" 200 400 600",
91
+ @convertor.instance_eval { make_thumbnails_cmd(3, 200, 150, nil, 2) }
92
+ end # }}}
55
93
  end
94
+ #}}}
95
+ context "when source file is available locally" do # {{{
96
+ setup do
97
+ @convertor.file = Factory(:file, :filename => 'test.avi', :location => 'ftp://example.com/test.avi')
98
+ FileUtils.touch '/tmp/test.avi'
99
+ Net::FTP.expects(:open).never
100
+ end
101
+ should "return immediately on attempt to fetch file" do
102
+ assert_nil @convertor.instance_eval { fetch_file('ftp://example.com/test.avi', 'test.avi') }
103
+ end
104
+ end
105
+ # }}}
106
+ context "when source file is not available locally" do # {{{
107
+ setup do
108
+ @convertor.file = Factory(:file, :filename => 'test.avi', :location => 'ftp://example.com/test.avi')
109
+ FileUtils.rm_rf '/tmp/test.avi'
110
+ end
111
+
112
+ context "and ftp server works fine" do
113
+ setup do
114
+ ftp = mock()
115
+ ftp.expects(:login).with('test','test')
116
+ ftp.expects(:getbinaryfile).with('test.avi', '/tmp/test/test.part', 1024)
117
+ ftp.expects(:close)
118
+ Net::FTP.expects(:new).with('example.com', nil, nil, nil).returns(ftp)
119
+ end
120
+ should "download file by FTP" do
121
+ assert_equal 0, @convertor.instance_eval { fetch_file('ftp://example.com/test.avi', 'test.avi') }
122
+ assert !File.exists?('/tmp/test/test.avi.part')
123
+ assert File.exists?('/tmp/test.avi')
124
+ end
125
+ end
126
+
127
+ context "and ftp server doesn't work" do
128
+ setup do
129
+ ftp = mock()
130
+ ftp.expects(:login).with('test','test')
131
+ ftp.expects(:getbinaryfile).raises(Net::FTPError)
132
+ ftp.expects(:close)
133
+ Net::FTP.expects(:new).with('example.com', nil, nil, nil).returns(ftp)
134
+ end
135
+ should "remove tmp file and raise error" do
136
+ assert_raise Net::FTPError do
137
+ @convertor.instance_eval { fetch_file('ftp://example.com/test.avi', 'test.avi') }
138
+ end
139
+ assert !File.exists?('/tmp/test/test.avi.part')
140
+ end
141
+ end
142
+ end
143
+ # }}}
144
+ context "processing file with some profile" do # {{{
145
+ setup do
146
+ @convertor.file = Factory(:file, :filename => 'x/y/test.avi')
147
+ @convertor.logger = Logger.new('/dev/null')
148
+ @convertor.expects(:mkcmd).twice.returns("echo OK > /dev/null").then.returns("echo OK > test-sd-0.mp4")
149
+ Convertr::Config.any_instance.stubs(:qtfaststart => 'mv')
150
+ @convertor.instance_eval { process_profile('sd') }
151
+ end
152
+ should "create converted file" do
153
+ assert File.exists?('/tmp/output/x/y/test-sd.mp4')
154
+ end
155
+ should "remove temporary dir" do
156
+ assert !File.exists?('sd')
157
+ end
158
+ end
159
+ # }}}
160
+ context "successfuly processing some task" do
161
+ setup do
162
+ file = Factory(:file, :filename => 'test.avi', :location => 'ftp://example.com/test.avi', :duration => 600)
163
+ @convertor.task = Factory(:task, :file => file, :bitrate => 600)
164
+ @convertor.logger = Logger.new('/dev/null')
165
+ FileUtils.mkpath('/tmp/test')
166
+ processing = sequence('processing')
167
+ @convertor.expects(:fetch_file).with('ftp://example.com/test.avi', 'test.avi').in_sequence(processing).returns(true)
168
+ @convertor.expects(:process_profile).with('hd').in_sequence(processing).returns(true)
169
+ @convertor.expects(:make_thumbnails_cmd).with(3, 200, 150, nil, 2).in_sequence(processing).returns('echo OK>/dev/null')
170
+ end
171
+ should "return SUCCESS" do
172
+ assert_equal 'SUCCESS', @convertor.instance_eval { process_task }
173
+ end
174
+ end
175
+ context "getting ftp error on processing some task" do
176
+ setup do
177
+ file = Factory(:file, :filename => 'test.avi', :location => 'ftp://example.com/test.avi', :duration => 600)
178
+ @convertor.task = Factory(:task, :file => file, :bitrate => 600)
179
+ @convertor.logger = Logger.new('/dev/null')
180
+ FileUtils.mkpath('/tmp/test')
181
+ @convertor.expects(:fetch_file).with('ftp://example.com/test.avi', 'test.avi').raises(Net::FTPError)
182
+ @convertor.expects(:process_profile).never
183
+ @convertor.expects(:make_thumbnails_cmd).never
184
+ end
185
+ should "return FAILURE" do
186
+ assert_equal 'FAILURE', @convertor.instance_eval { process_task }
187
+ end
188
+ end
189
+ end
190
+
191
+ context "Convertor ran with max_tasks=2" do
192
+ setup do
193
+ @convertor = Convertr::Convertor.new(2)
194
+ end
195
+
196
+ context "after successful processing first and failure on second task" do # {{{
197
+ setup do
198
+ @task_success = Factory(:task)
199
+ @task_failure = Factory(:task)
200
+ @convertor.scheduler.stubs(:schedule_next_task).returns(@task_success).then.returns(@task_failure)
201
+ @convertor.stubs(:process_task).returns('SUCCESS').then.returns('FAILURE')
202
+ @convertor.run
203
+ end
204
+ should "exit" do
205
+ assert_equal 2, @convertor.tasks
206
+ end
207
+ should "update first task with success" do
208
+ assert_equal 'SUCCESS', @task_success.convert_status
209
+ assert_in_delta Time.now.to_i, @task_success.convert_stopped_at.to_i, 1
210
+ end
211
+ should "update second task with failure" do
212
+ assert_equal 'FAILURE', @task_failure.convert_status
213
+ assert_in_delta Time.now.to_i, @task_failure.convert_stopped_at.to_i, 1
214
+ end
215
+ end # }}}
56
216
  end
57
217
  end
@@ -4,13 +4,11 @@ class TestFile < Test::Unit::TestCase
4
4
  context "File class" do
5
5
  should "have without_convertor scope" do
6
6
  files = Convertr::File.without_convertor
7
- assert_equal 2, files.size
8
7
  assert_equal 3, files.first.id
9
8
  end
10
9
 
11
10
  should "have with_convertor scope" do
12
11
  files = Convertr::File.with_convertor('convertor1')
13
- assert_equal 2, files.size
14
12
  assert_equal 1, files.first.id
15
13
  end
16
14
  end
@@ -5,10 +5,28 @@ class TestScheduler < Test::Unit::TestCase
5
5
  setup do
6
6
  @scheduler = Convertr::Scheduler::Base.new
7
7
  end
8
+
8
9
  should "raise exception on calling abstract methods" do
9
10
  assert_raise RuntimeError do
10
11
  @scheduler.instance_eval { get_task_for_schedule('convertor1') }
11
12
  end
12
13
  end
14
+
15
+ context "after scheduling next task" do
16
+ setup do
17
+ @task = Factory.build :task
18
+ @scheduler.expects(:get_task_for_schedule).with('convertor1').returns(@task)
19
+ @scheduler.schedule_next_task('convertor1')
20
+ end
21
+
22
+ should "update task accordingly" do
23
+ assert_equal 'PROGRESS', @task.convert_status
24
+ assert_in_delta Time.now.to_i, @task.convert_started_at.to_i, 1
25
+ end
26
+
27
+ should "update file accordingly" do
28
+ assert_equal "convertor1", @task.file.convertor
29
+ end
30
+ end
13
31
  end
14
32
  end
@@ -6,7 +6,7 @@ class TestSchedulerAllbtfirst < Test::Unit::TestCase
6
6
  @scheduler = Convertr::SchedulerFactory.create('AllBtFirst')
7
7
  end
8
8
  should "find first task assigned for convertor" do
9
- assert_equal 2, @scheduler.get_task_for_schedule('convertor1').id
9
+ assert_equal 3, @scheduler.get_task_for_schedule('convertor1').id
10
10
  end
11
11
  end
12
12
  end
@@ -8,6 +8,9 @@ class TestTask < Test::Unit::TestCase
8
8
  should "have not_completed scope" do
9
9
  assert_equal 3, Convertr::Task.not_completed.size
10
10
  end
11
+ should "have without_convertor scope" do
12
+ assert_equal 1, Convertr::Task.without_convertor.first.id
13
+ end
11
14
  end
12
15
 
13
16
  context "Task" do
metadata CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
+ - 1
8
9
  - 0
9
- - 2
10
- version: 0.0.2
10
+ version: 0.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ilya Lityuga
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-10-13 00:00:00 +04:00
19
+ date: 2010-10-14 00:00:00 +04:00
20
20
  default_executable: convertr
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency