convertr 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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