quorum 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/Gemfile.lock +42 -48
  2. data/HISTORY.md +11 -0
  3. data/app/assets/javascripts/quorum/quorum.js +8 -5
  4. data/db/migrate/20120807202555_add_gaps_to_blast_reports.rb +8 -0
  5. data/lib/generators/templates/blast.rb +76 -40
  6. data/lib/quorum/version.rb +1 -1
  7. data/quorum.gemspec +6 -7
  8. data/spec/data/fake_seq.txt +2 -0
  9. data/spec/data/nucl_prot_seqs.txt +15 -0
  10. data/spec/data/tmp/test.tgz +0 -0
  11. data/spec/dummy/config/initializers/quorum_initializer.rb +1 -1
  12. data/spec/dummy/config/quorum_settings.yml +5 -9
  13. data/spec/dummy/db/schema.rb +23 -19
  14. data/spec/dummy/quorum/bin/fetch +3 -3
  15. data/spec/dummy/quorum/bin/search +8 -8
  16. data/spec/dummy/quorum/blastdb/test/contigs.fa +13 -0
  17. data/spec/dummy/quorum/blastdb/test/peptides.fa +2 -0
  18. data/spec/dummy/quorum/blastdb/test.nhd +1 -0
  19. data/spec/dummy/quorum/blastdb/test.nhi +0 -0
  20. data/spec/dummy/quorum/blastdb/test.nhr +0 -0
  21. data/spec/dummy/quorum/blastdb/test.nin +0 -0
  22. data/spec/dummy/quorum/blastdb/test.nog +0 -0
  23. data/spec/dummy/quorum/blastdb/test.nsd +1 -0
  24. data/spec/dummy/quorum/blastdb/test.nsi +0 -0
  25. data/spec/dummy/quorum/blastdb/test.nsq +0 -0
  26. data/spec/dummy/quorum/blastdb/test.phd +1 -0
  27. data/spec/dummy/quorum/blastdb/test.phi +0 -0
  28. data/spec/dummy/quorum/blastdb/test.phr +0 -0
  29. data/spec/dummy/quorum/blastdb/test.pin +0 -0
  30. data/spec/dummy/quorum/blastdb/test.pog +0 -0
  31. data/spec/dummy/quorum/blastdb/test.psd +1 -0
  32. data/spec/dummy/quorum/blastdb/test.psi +0 -0
  33. data/spec/dummy/quorum/blastdb/test.psq +0 -0
  34. data/spec/dummy/quorum/lib/fetch_tools/blast_db.rb +6 -6
  35. data/spec/dummy/quorum/lib/logger.rb +4 -4
  36. data/spec/dummy/quorum/lib/search_tools/blast.rb +76 -40
  37. data/spec/dummy/quorum/lib/trollop.rb +4 -4
  38. data/spec/javascripts/fixtures/formatted_sequence.html +1 -1
  39. data/spec/javascripts/quorum_spec.js +8 -6
  40. data/spec/requests/jobs_spec.rb +13 -3
  41. data/spec/spec_helper.rb +0 -4
  42. data/spec/templates/blast_spec.rb +53 -3
  43. metadata +17 -31
@@ -33,8 +33,8 @@ Options:
33
33
  HEAD
34
34
 
35
35
  # Search tool
36
- opt :search_tool, "Search tool to execute. Available tools: " <<
37
- "#{SEARCH_TOOLS.keys.join(', ')}", :type => :string,
36
+ opt :search_tool, "Search tool to execute. Available tools: " <<
37
+ "#{SEARCH_TOOLS.keys.join(', ')}", :type => :string,
38
38
  :required => true, :short => "-s"
39
39
 
40
40
  # General settings
@@ -48,19 +48,19 @@ Options:
48
48
  :short => "-i"
49
49
  opt :database, "Database name", :type => :string, :required => true,
50
50
  :short => "-d"
51
- opt :database_adapter, "ActiveRecord database adapter",
51
+ opt :database_adapter, "ActiveRecord database adapter",
52
52
  :type => :string, :required => true, :short => "-a"
53
- opt :database_host, "Database host", :type => :string,
53
+ opt :database_host, "Database host", :type => :string,
54
54
  :required => true, :short => "-k"
55
- opt :database_user, "Database username", :type => :string,
55
+ opt :database_user, "Database username", :type => :string,
56
56
  :required => true, :short => "-u"
57
57
  opt :database_password, "Database password", :type => :string,
58
58
  :required => true, :short => "-p"
59
-
59
+
60
60
  # Global settings
61
61
  opt :search_database, "Path to search tool database", :type => :string,
62
62
  :short => "-b"
63
- opt :threads, "Number of threads to spawn for search tool",
63
+ opt :threads, "Number of threads to spawn for search tool",
64
64
  :type => :int, :short => "-t"
65
65
  end
66
66
 
@@ -136,6 +136,6 @@ Options:
136
136
  end
137
137
 
138
138
  if __FILE__ == $0
139
- Quorum::Search.new
139
+ Quorum::Search.new
140
140
  end
141
141
 
@@ -1,2 +1,15 @@
1
1
  >TOG900080
2
2
  TGATAGGATAATTCTAGACAAAACATTAGCCGATCAAGTGTCATCATGGAAAAGCAGCAGGGGCCTTAGTGATACAGTGGTGACTGATCATGCTTGTTCTGGGGAAACATGCTCGTACTACGCAATTGGAGATGTATTTATTTGTGAAAAGACTGGACAAGTTCATGTTTGTGACGAAACATGTAGGGAAGTAGTAATGGATCCCACCAACGAGCTTTTGGTCTGTACAATATCTGGCCACTGTTTTGACAGATTGCTATCACCTGCTGAAATGGAGCCTGATGCTGAGCAGCAGCAAGGTGGTGCGGCAGATGAGGCAGAACCGTTTATGGGATCTGGCCGTTTTGCACGGGCTTATTTGCTGGGATACAATTGTGCTGATGAAAAGGAGCTTGAAGCTACTTTGAGGTTTTGCTGATCCCTATTGGCCCTTCTGGAGTGGATGATCTCATGTCTCAGCATTTACCTATTTAAGATCAAATAAATCGGGTTTCCTTTTCGTGTTTCTCTTGGCATAAGAATGTTTGATTAGATCTAGATTATGAAACTCTAATCGTCTTCTATATTAATAATTGTATGCTTAAATTTATAGTTGAAATTCCATTGATGAATTTTTCTT
3
+ >reverse translation of ADA84676.1 protein L-isoaspartyl methyltransferase 1 [Cicer arietinum] to a 687 base sequence of most likely codons.
4
+ atggaacagtattggagcggcagcgcgattaacgaaaacaaaggcatggtggaaaacctg
5
+ cagcgctatggcattattaaaagcagcaaagtggcggaaaccatggaaaaaattgatcgc
6
+ ggcctgtttgtgccgaacggcgtgcagccgtatattgatagcccgatgagcattggctat
7
+ aacgcgaccattagcgcgccgcatatgcatgcgacctgcctgcagctgctggaaaactat
8
+ ctgcagccgggcatgcatgcgctggatgtgggcagcggcaccggctatctgaccgcgtgc
9
+ tttgcgatgatggtgggcccgaacggccgcgcggtgggcgtggaacatattccggaactg
10
+ gtgagctttagcattaacaacattgaaaaaagcgcggcggcgccgcagctgaaagatggc
11
+ agcctgagcgtgcatgaaggcgatggccgccagggctggccggaatttgcgacctatgat
12
+ gcgattcatgtgggcgcggcggcgccggaaattccgcagccgctgattgatcagctgaaa
13
+ accggcggccgcatgattattccggtgggcaacgtgtttcaggatctgaaagtggtggat
14
+ aaaaacagcgatggcagcattagcattcgcaccgaaaccagcgtgcgctatgtgccgctg
15
+ accagcaaagaagcgcagctgaaagaa
@@ -1,2 +1,4 @@
1
1
  >ADA84676.1 protein L-isoaspartyl methyltransferase 1 [Cicer arietinum]
2
2
  MEQYWSGSAINENKGMVENLQRYGIIKSSKVAETMEKIDRGLFVPNGVQPYIDSPMSIGYNATISAPHMHATCLQLLENYLQPGMHALDVGSGTGYLTACFAMMVGPNGRAVGVEHIPELVSFSINNIEKSAAAPQLKDGSLSVHEGDGRQGWPEFATYDAIHVGAAAPEIPQPLIDQLKTGGRMIIPVGNVFQDLKVVDKNSDGSISIRTETSVRYVPLTSKEAQLKE
3
+ >VIRT10447
4
+ TVLPHLPHHLAAAQHQAPFQQVIAICQNSGQILYRPKARWWDPLLLPYMFRHKHELVQSFHK
@@ -1 +1,2 @@
1
+ 34432766131
1
2
  8824380950
Binary file
Binary file
Binary file
Binary file
@@ -1 +1,2 @@
1
1
  gnl|bl_ord_id|00
2
+ gnl|bl_ord_id|11
Binary file
Binary file
@@ -1 +1,2 @@
1
+ 24330897691
1
2
  28413460680
Binary file
Binary file
Binary file
Binary file
@@ -1 +1,2 @@
1
1
  gnl|bl_ord_id|00
2
+ gnl|bl_ord_id|11
Binary file
Binary file
@@ -77,10 +77,10 @@ module Quorum
77
77
  #
78
78
  # Execute the blastdbcmd(s) and return the matching sequence.
79
79
  #
80
- # To make Blast execute as quickly as possible, each selected
81
- # algorithm blasts against all supplied databases at once.
82
- #
83
- # See quorum/lib/search_tools/blast.rb for more information.
80
+ # To make Blast execute as quickly as possible, each selected
81
+ # algorithm blasts against all supplied databases at once.
82
+ #
83
+ # See quorum/lib/search_tools/blast.rb for more information.
84
84
  #
85
85
  # One consequence of this is not knowing which Blast database to use
86
86
  # when retrieving a hit sequence via blastdbcmd.
@@ -93,10 +93,10 @@ module Quorum
93
93
  def execute_blast_db_cmd
94
94
  generate_blast_db_cmds
95
95
  @logger.log("NCBI Blast", @cmds.join('; '))
96
-
96
+
97
97
  @seqs = ""
98
98
  @cmds.each { |c| @seqs << `#{c} 2> /dev/null` }
99
-
99
+
100
100
  seq = parse_and_send_results
101
101
  $stdout.print seq
102
102
  end
@@ -29,13 +29,13 @@ module Quorum
29
29
  # Removes instance files.
30
30
  #
31
31
  def remove_files(files)
32
- unless Dir.glob(files).empty?
33
- `rm #{files}`
34
- else
35
- log(
32
+ if Dir.glob(files).empty?
33
+ log(
36
34
  "remove_files",
37
35
  "Unable to remove #{files}"
38
36
  )
37
+ else
38
+ `rm #{files}`
39
39
  end
40
40
  end
41
41
 
@@ -126,6 +126,9 @@ module Quorum
126
126
  Digest::MD5.hexdigest(sequence).to_s + "-" + Time.now.to_f.to_s
127
127
  end
128
128
 
129
+ #
130
+ # Blastn command
131
+ #
129
132
  def generate_blastn_cmd
130
133
  blastn = "blastn " <<
131
134
  "-db \"#{@db}\" " <<
@@ -145,6 +148,9 @@ module Quorum
145
148
  blastn
146
149
  end
147
150
 
151
+ #
152
+ # Blastx command
153
+ #
148
154
  def generate_blastx_cmd
149
155
  blastx = "blastx " <<
150
156
  "-db \"#{@db}\" " <<
@@ -164,6 +170,9 @@ module Quorum
164
170
  blastx
165
171
  end
166
172
 
173
+ #
174
+ # Tblastn command
175
+ #
167
176
  def generate_tblastn_cmd
168
177
  tblastn = "tblastn " <<
169
178
  "-db \"#{@db}\" " <<
@@ -185,6 +194,9 @@ module Quorum
185
194
  tblastn
186
195
  end
187
196
 
197
+ #
198
+ # Blastp command
199
+ #
188
200
  def generate_blastp_cmd
189
201
  blastp = "blastp " <<
190
202
  "-db \"#{@db}\" " <<
@@ -256,12 +268,65 @@ module Quorum
256
268
  end
257
269
 
258
270
  #
259
- # Parse and save Blast results using bio-blastxmlparser.
260
- # Only save Blast results if results.bit_score > @min_score.
271
+ # Save Blast Job Report
272
+ #
273
+ # Hsps are only reported if a query hit against the Blast db.
274
+ # Only save the @data if bit_score exists and it's > the user
275
+ # defined minimum score.
276
+ #
277
+ # Set the attribute results to true for downstream processes.
278
+ #
279
+ def save_hsp_results
280
+ if @data[:bit_score] && (@data[:bit_score].to_i > @min_score.to_i)
281
+ @data[:results] = true
282
+ @data["#{@algorithm}_job_id".to_sym] = @job.method(@job_association).call.job_id
283
+
284
+ job_report = @job.method(@job_report_association).call.build(@data)
285
+
286
+ unless job_report.save!
287
+ @logger.log(
288
+ "ActiveRecord",
289
+ "Unable to save #{@algorithm} results to database.",
290
+ 1,
291
+ @tmp_files
292
+ )
293
+ end
294
+ end
295
+ end
296
+
297
+ #
298
+ # Save empty Blast Job Report
299
+ #
300
+ # Set the attribute results to false for downstream processes.
301
+ #
302
+ def save_empty_results
303
+ job_report = @job.method(@job_report_association).call.build(
304
+ "#{@algorithm}_job_id" => @job.method(@job_association).call.job_id,
305
+ "results" => false
306
+ )
307
+ unless job_report.save!
308
+ @logger.log(
309
+ "ActiveRecord",
310
+ "Unable to save #{@algorithm} results to database.",
311
+ 1,
312
+ @tmp_files
313
+ )
314
+ end
315
+ @logger.log(
316
+ "NCBI Blast",
317
+ "#{@algorithm} report empty.",
318
+ 0,
319
+ @tmp_files
320
+ )
321
+ end
322
+
323
+ #
324
+ # Parse and save Blast results.
325
+ #
326
+ # Parse the Blast XML output and save results.
261
327
  #
262
328
  def parse_and_save_results
263
- # Helper to avoid having to perform a query.
264
- saved = false
329
+ @results = false # Did the xml contain results?
265
330
 
266
331
  if File.size(@out) > 0
267
332
  report = Bio::Blast::XmlIterator.new(@out)
@@ -292,28 +357,16 @@ module Quorum
292
357
  @data[:hit_frame] = hsp.hit_frame
293
358
  @data[:identity] = hsp.identity
294
359
  @data[:positive] = hsp.positive
360
+ @data[:gaps] = hsp.gaps
295
361
  @data[:align_len] = hsp.align_len
296
362
  @data[:qseq] = hsp.qseq
297
363
  @data[:hseq] = hsp.hseq
298
364
  @data[:midline] = hsp.midline
299
365
 
300
- # Hsps are only reported if a query hit against the Blast db.
301
- # Only save the @data if bit_score exists.
302
366
  if @data[:bit_score] &&
303
367
  (@data[:bit_score].to_i > @min_score.to_i)
304
- @data[:results] = true
305
- @data["#{@algorithm}_job_id".to_sym] = @job.method(@job_association).call.job_id
306
- saved = true
307
- # Build a new report for each Hsp.
308
- job_report = @job.method(@job_report_association).call.build(@data)
309
- unless job_report.save!
310
- @logger.log(
311
- "ActiveRecord",
312
- "Unable to save #{@algorithm} results to database.",
313
- 1,
314
- @tmp_files
315
- )
316
- end
368
+ @results = true
369
+ save_hsp_results
317
370
  end
318
371
 
319
372
  end
@@ -321,27 +374,7 @@ module Quorum
321
374
  end
322
375
  end
323
376
 
324
- # Save the record and set results to false.
325
- unless saved
326
- job_report = @job.method(@job_report_association).call.build(
327
- "#{@algorithm}_job_id" => @job.method(@job_association).call.job_id,
328
- "results" => false
329
- )
330
- unless job_report.save!
331
- @logger.log(
332
- "ActiveRecord",
333
- "Unable to save #{@algorithm} results to database.",
334
- 1,
335
- @tmp_files
336
- )
337
- end
338
- @logger.log(
339
- "NCBI Blast",
340
- "#{@algorithm} report empty.",
341
- 0,
342
- @tmp_files
343
- )
344
- end
377
+ save_empty_results unless @results
345
378
  end
346
379
 
347
380
  #
@@ -388,6 +421,9 @@ module Quorum
388
421
  end
389
422
  end
390
423
 
424
+ #
425
+ # Remove tmp files.
426
+ #
391
427
  def remove_tmp_files
392
428
  `rm #{@tmp_files}` if @tmp_files
393
429
  end
@@ -12,7 +12,7 @@ VERSION = "1.16.2"
12
12
  ## Thrown by Parser in the event of a commandline error. Not needed if
13
13
  ## you're using the Trollop::options entry.
14
14
  class CommandlineError < StandardError; end
15
-
15
+
16
16
  ## Thrown by Parser if the user passes in '-h' or '--help'. Handled
17
17
  ## automatically by Trollop#options.
18
18
  class HelpNeeded < StandardError; end
@@ -250,7 +250,7 @@ class Parser
250
250
  syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
251
251
  @constraints << [:depends, syms]
252
252
  end
253
-
253
+
254
254
  ## Marks two (or more!) options as conflicting.
255
255
  def conflicts *syms
256
256
  syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
@@ -426,7 +426,7 @@ class Parser
426
426
  # call this unless the cursor's at the beginning of a line.
427
427
 
428
428
  left = {}
429
- @specs.each do |name, spec|
429
+ @specs.each do |name, spec|
430
430
  left[name] = "--#{spec[:long]}" +
431
431
  (spec[:short] && spec[:short] != :none ? ", -#{spec[:short]}" : "") +
432
432
  case spec[:type]
@@ -647,7 +647,7 @@ private
647
647
  start = 0
648
648
  ret = []
649
649
  until start > str.length
650
- nextt =
650
+ nextt =
651
651
  if start + width >= str.length
652
652
  str.length
653
653
  else
@@ -1,4 +1,4 @@
1
- <p class='small'>Alignment (Mouse over for positions):</p><span class='small'><pre>
1
+ <p class='small'>Alignment (Mouse over for positions):</p><span class='small sequence'><pre>
2
2
  qseq <a rel='quorum-tipsy' title=10>E</a><a rel='quorum-tipsy' title=11>L</a><a rel='quorum-tipsy' title=12>V</a><a rel='quorum-tipsy' title=13>I</a><a rel='quorum-tipsy' title=14>S</a>
3
3
  ELVIS
4
4
  hseq <a rel='quorum-tipsy' title=121>E</a><a rel='quorum-tipsy' title=122>L</a><a rel='quorum-tipsy' title=123>V</a><a rel='quorum-tipsy' title=124>I</a><a rel='quorum-tipsy' title=125>S</a>
@@ -77,7 +77,7 @@ describe("QUORUM", function() {
77
77
  var report = QUORUM.formatSequenceReport(
78
78
  "ACGT", "|| |", "ACCT", 6, 9, 2, 8, "blastn"
79
79
  );
80
- expect(report).toEqual("<p class='small'>Alignment (Mouse over for positions):</p><span class='small'><pre>\nqseq <a rel='quorum-tipsy' title=6>A</a><a rel='quorum-tipsy' title=7>C</a><a rel='quorum-tipsy' title=8>G</a><a rel='quorum-tipsy' title=9>T</a>\n || |\nhseq <a rel='quorum-tipsy' title=2>A</a><a rel='quorum-tipsy' title=3>C</a><a rel='quorum-tipsy' title=4>C</a><a rel='quorum-tipsy' title=5>T</a>\n\n</pre></span>");
80
+ expect(report).toEqual("<p class='small'>Alignment (Mouse over for positions):</p><span class='small sequence'><pre>\nqseq <a rel='quorum-tipsy' title=6>A</a><a rel='quorum-tipsy' title=7>C</a><a rel='quorum-tipsy' title=8>G</a><a rel='quorum-tipsy' title=9>T</a>\n || |\nhseq <a rel='quorum-tipsy' title=2>A</a><a rel='quorum-tipsy' title=3>C</a><a rel='quorum-tipsy' title=4>C</a><a rel='quorum-tipsy' title=5>T</a>\n\n</pre></span>");
81
81
  });
82
82
 
83
83
  //
@@ -89,7 +89,7 @@ describe("QUORUM", function() {
89
89
  var report = QUORUM.formatSequenceReport(
90
90
  "ACGT", "|| |", "ACCT", 6, 9, 2, 8, "blastx"
91
91
  );
92
- expect(report).toEqual("<p class='small'>Alignment (Mouse over for positions):</p><span class='small'><pre>\nqseq <a rel='quorum-tipsy' title=6>A</a><a rel='quorum-tipsy' title=9>C</a><a rel='quorum-tipsy' title=12>G</a><a rel='quorum-tipsy' title=15>T</a>\n || |\nhseq <a rel='quorum-tipsy' title=2>A</a><a rel='quorum-tipsy' title=3>C</a><a rel='quorum-tipsy' title=4>C</a><a rel='quorum-tipsy' title=5>T</a>\n\n</pre></span>");
92
+ expect(report).toEqual("<p class='small'>Alignment (Mouse over for positions):</p><span class='small sequence'><pre>\nqseq <a rel='quorum-tipsy' title=6>A</a><a rel='quorum-tipsy' title=9>C</a><a rel='quorum-tipsy' title=12>G</a><a rel='quorum-tipsy' title=15>T</a>\n || |\nhseq <a rel='quorum-tipsy' title=2>A</a><a rel='quorum-tipsy' title=3>C</a><a rel='quorum-tipsy' title=4>C</a><a rel='quorum-tipsy' title=5>T</a>\n\n</pre></span>");
93
93
  });
94
94
 
95
95
  //
@@ -101,7 +101,7 @@ describe("QUORUM", function() {
101
101
  var report = QUORUM.formatSequenceReport(
102
102
  "ELVIS", "ELVIS", "ELVIS", 10, 14, 121, 136, "tblastn"
103
103
  );
104
- expect(report).toEqual("<p class='small'>Alignment (Mouse over for positions):</p><span class='small'><pre>\nqseq <a rel='quorum-tipsy' title=10>E</a><a rel='quorum-tipsy' title=11>L</a><a rel='quorum-tipsy' title=12>V</a><a rel='quorum-tipsy' title=13>I</a><a rel='quorum-tipsy' title=14>S</a>\n ELVIS\nhseq <a rel='quorum-tipsy' title=121>E</a><a rel='quorum-tipsy' title=124>L</a><a rel='quorum-tipsy' title=127>V</a><a rel='quorum-tipsy' title=130>I</a><a rel='quorum-tipsy' title=133>S</a>\n\n</pre></span>");
104
+ expect(report).toEqual("<p class='small'>Alignment (Mouse over for positions):</p><span class='small sequence'><pre>\nqseq <a rel='quorum-tipsy' title=10>E</a><a rel='quorum-tipsy' title=11>L</a><a rel='quorum-tipsy' title=12>V</a><a rel='quorum-tipsy' title=13>I</a><a rel='quorum-tipsy' title=14>S</a>\n ELVIS\nhseq <a rel='quorum-tipsy' title=121>E</a><a rel='quorum-tipsy' title=124>L</a><a rel='quorum-tipsy' title=127>V</a><a rel='quorum-tipsy' title=130>I</a><a rel='quorum-tipsy' title=133>S</a>\n\n</pre></span>");
105
105
  });
106
106
 
107
107
  //
@@ -113,16 +113,18 @@ describe("QUORUM", function() {
113
113
  var report = QUORUM.formatSequenceReport(
114
114
  "ELVIS", "ELVIS", "ELVIS", 10, 14, 121, 125, "blastp"
115
115
  );
116
- expect(report).toEqual("<p class='small'>Alignment (Mouse over for positions):</p><span class='small'><pre>\nqseq <a rel='quorum-tipsy' title=10>E</a><a rel='quorum-tipsy' title=11>L</a><a rel='quorum-tipsy' title=12>V</a><a rel='quorum-tipsy' title=13>I</a><a rel='quorum-tipsy' title=14>S</a>\n ELVIS\nhseq <a rel='quorum-tipsy' title=121>E</a><a rel='quorum-tipsy' title=122>L</a><a rel='quorum-tipsy' title=123>V</a><a rel='quorum-tipsy' title=124>I</a><a rel='quorum-tipsy' title=125>S</a>\n\n</pre></span>");
116
+ expect(report).toEqual("<p class='small'>Alignment (Mouse over for positions):</p><span class='small sequence'><pre>\nqseq <a rel='quorum-tipsy' title=10>E</a><a rel='quorum-tipsy' title=11>L</a><a rel='quorum-tipsy' title=12>V</a><a rel='quorum-tipsy' title=13>I</a><a rel='quorum-tipsy' title=14>S</a>\n ELVIS\nhseq <a rel='quorum-tipsy' title=121>E</a><a rel='quorum-tipsy' title=122>L</a><a rel='quorum-tipsy' title=123>V</a><a rel='quorum-tipsy' title=124>I</a><a rel='quorum-tipsy' title=125>S</a>\n\n</pre></span>");
117
117
  });
118
118
 
119
119
  //
120
120
  // jQuery tipsy plugin should display anchor's title attribute on mouseover
121
121
  // and hide on mouseout.
122
122
  //
123
- it("should display title via jquery.tipsy on mouse over hide on mouse out", function() {
123
+ it("should display title via jquery.tipsy on mouse over and hide on mouse out", function() {
124
124
  loadFixtures('formatted_sequence.html');
125
- $('a[rel=quorum-tipsy]').tipsy({ gravity: 's' });
125
+ $('.sequence').mouseenter(function() {
126
+ $(this).find('a[rel=quorum-tipsy]').tipsy({ gravity: 's' });
127
+ });
126
128
 
127
129
  $('a[rel=quorum-tipsy]').trigger('mouseover');
128
130
  expect($('.tipsy')).toBeVisible();
@@ -110,10 +110,20 @@ describe "Jobs" do
110
110
  page.should have_content("Search Results")
111
111
 
112
112
  click_link "Blastx"
113
- page.should have_content("Your search returned 0 hits.")
113
+
114
+ # Render modal box.
115
+ find("#blastx-results").find("td a").click
116
+ page.should have_content("Quorum Report Details")
117
+ page.should have_content("qseq")
118
+ page.should have_content("hseq")
114
119
 
115
120
  click_link "Tblastn"
116
- page.should have_content("Your search returned 0 hits.")
121
+
122
+ # Render modal box.
123
+ find("#tblastn-results").find("td a").click
124
+ page.should have_content("Quorum Report Details")
125
+ page.should have_content("qseq")
126
+ page.should have_content("hseq")
117
127
 
118
128
  ## Interact with the Blast results. ##
119
129
  click_link "Blastn"
@@ -125,7 +135,7 @@ describe "Jobs" do
125
135
  page.should have_content("hseq")
126
136
 
127
137
  # Download sequence
128
- find("p.small a#download_sequence_1").click
138
+ find("p.small a#download_sequence_2").click
129
139
  page.should have_content("Fetching sequence...")
130
140
  page.should have_content("Sequence Downloaded Successfully")
131
141
 
data/spec/spec_helper.rb CHANGED
@@ -3,13 +3,9 @@ ENV["RAILS_ENV"] ||= 'test'
3
3
  require File.expand_path("../dummy/config/environment.rb", __FILE__)
4
4
  require 'rspec/rails'
5
5
  require 'capybara/rspec'
6
- require 'factory_girl'
7
6
  require 'database_cleaner'
8
7
  require 'resque_spec'
9
8
 
10
- FactoryGirl.definition_file_paths << File.join(File.dirname(__FILE__), 'factories')
11
- FactoryGirl.find_definitions
12
-
13
9
  ENGINE_RAILS_ROOT = File.expand_path("../../", __FILE__)
14
10
 
15
11
  # Requires supporting ruby files with custom matchers and macros, etc,
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
  require File.expand_path("../../dummy/quorum/lib/search_tools/blast", __FILE__)
3
3
 
4
4
  describe "Quorum::SearchTools::Blast" do
5
- describe "#execute_blast" do
5
+ describe "#execute_blast non empty report" do
6
6
  before(:each) do
7
7
  # Set args as though we executed bin/search.
8
8
  @args = {
@@ -69,7 +69,7 @@ describe "Quorum::SearchTools::Blast" do
69
69
  blast = Quorum::SearchTools::Blast.new(@args)
70
70
  expect {
71
71
  blast.execute_blast
72
- }.to raise_error(SystemExit)
72
+ }.to_not raise_error
73
73
 
74
74
  Dir.glob(
75
75
  File.join(@args[:tmp_directory], "*")
@@ -86,7 +86,7 @@ describe "Quorum::SearchTools::Blast" do
86
86
  blast = Quorum::SearchTools::Blast.new(@args)
87
87
  expect {
88
88
  blast.execute_blast
89
- }.to raise_error(SystemExit)
89
+ }.to_not raise_error
90
90
 
91
91
  Dir.glob(
92
92
  File.join(@args[:tmp_directory], "*")
@@ -109,6 +109,56 @@ describe "Quorum::SearchTools::Blast" do
109
109
  File.join(@args[:tmp_directory], "*")
110
110
  ).length.should be == 0
111
111
  end
112
+ end
113
+
114
+ describe "#execute_blast empty report" do
115
+ before(:each) do
116
+ # Set args as though we executed bin/search.
117
+ @args = {
118
+ :search_tool => "blastn",
119
+ :id => nil,
120
+ :log_directory => File.expand_path(
121
+ "../../dummy/quorum/log", __FILE__
122
+ ),
123
+ :tmp_directory => File.expand_path(
124
+ "../../dummy/quorum/tmp", __FILE__
125
+ ),
126
+ :search_database => File.expand_path(
127
+ "../../dummy/quorum/blastdb", __FILE__
128
+ ),
129
+ :threads => 1
130
+ }
131
+
132
+ @job = Quorum::Job.new()
133
+
134
+ @job.sequence = File.open(
135
+ File.expand_path("../../data/fake_seq.txt", __FILE__)
136
+ ).read
137
+
138
+ @job.build_blastn_job
139
+ @job.blastn_job.queue = true
140
+ @job.blastn_job.blast_dbs = ["test"]
141
+ end
142
+
143
+ it "executes blastn on a given dataset and returns an empty report" do
144
+ @job.stub(:queue_workers)
145
+ @job.save!
146
+
147
+ @args[:id] = @job.id
148
+
149
+ blast = Quorum::SearchTools::Blast.new(@args)
150
+ expect {
151
+ blast.execute_blast
152
+ }.to raise_error
153
+
154
+ Dir.glob(
155
+ File.join(@args[:tmp_directory], "*")
156
+ ).length.should be == 0
157
+
158
+ log_file = File.join(@args[:log_directory], "quorum.log")
159
+
160
+ `tail -n 3 #{log_file}`.to_s.include?("blastn report empty").should be_true
161
+ end
112
162
 
113
163
  end
114
164
  end