quorum 0.3.3 → 0.4.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.
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