naf 2.1.12 → 2.1.13
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/Gemfile +4 -3
- data/RELEASE_NOTES.rdoc +17 -4
- data/app/assets/images/download.png +0 -0
- data/app/assets/javascripts/dataTablesTemplates/jobs.js +37 -0
- data/app/controllers/naf/historical_jobs_controller.rb +30 -0
- data/app/controllers/naf/log_parsers_controller.rb +9 -0
- data/app/helpers/naf/application_helper.rb +1 -1
- data/app/models/logical/naf/application_schedule.rb +7 -3
- data/app/models/logical/naf/log_parser/base.rb +1 -0
- data/app/models/logical/naf/log_parser/job.rb +4 -3
- data/app/models/logical/naf/log_parser/job_downloader.rb +156 -0
- data/app/models/logical/naf/log_parser/runner.rb +4 -3
- data/app/models/logical/naf/metric_sender.rb +62 -0
- data/app/models/process/naf/database_models_cleanup.rb +91 -0
- data/app/models/process/naf/runner.rb +52 -35
- data/app/views/naf/historical_jobs/_button_control.html.erb +64 -0
- data/app/views/naf/historical_jobs/index.json.erb +26 -5
- data/app/views/naf/historical_jobs/show.html.erb +20 -29
- data/app/views/naf/log_viewer/_job_log_download_button.html.erb +11 -0
- data/app/views/naf/log_viewer/_job_logs.html.erb +3 -0
- data/app/views/naf/log_viewer/_log_display.html.erb +4 -4
- data/app/views/naf/log_viewer/_log_layout.html.erb +5 -0
- data/config/routes.rb +4 -0
- data/lib/naf.rb +8 -0
- data/lib/naf/configuration.rb +5 -1
- data/lib/naf/version.rb +1 -1
- data/naf.gemspec +5 -2
- data/spec/controllers/naf/log_parsers_controller_spec.rb +35 -0
- data/spec/models/logical/naf/application_schedule_spec.rb +41 -0
- data/spec/models/logical/naf/construction_zone/boss_spec.rb +5 -0
- data/spec/models/logical/naf/construction_zone/foreman_spec.rb +6 -3
- data/spec/models/logical/naf/job_downloader_spec.rb +72 -0
- data/spec/models/logical/naf/job_statuses/errored_spec.rb +33 -0
- data/spec/models/logical/naf/job_statuses/finished_less_minute_spec.rb +33 -0
- data/spec/models/logical/naf/job_statuses/finished_spec.rb +33 -0
- data/spec/models/logical/naf/job_statuses/queued_spec.rb +34 -0
- data/spec/models/logical/naf/job_statuses/running_spec.rb +37 -0
- data/spec/models/logical/naf/job_statuses/terminated_spec.rb +33 -0
- data/spec/models/logical/naf/job_statuses/waiting_spec.rb +33 -0
- metadata +80 -6
@@ -137,6 +137,18 @@
|
|
137
137
|
"#", { class: "terminate" }
|
138
138
|
%></td>
|
139
139
|
</tr>
|
140
|
+
<% elsif !['Terminating'].include?(@logical_job.status) -%>
|
141
|
+
<tr>
|
142
|
+
<td>Enqueue Application</td>
|
143
|
+
<td><% params = { class: "re-enqueue", content: "#{naf.historical_jobs_path}/reenqueue", id: @historical_job.id } %>
|
144
|
+
<% if @historical_job.application_id.present? -%>
|
145
|
+
<% params[:app_id] = @historical_job.application.id %>
|
146
|
+
<% end %>
|
147
|
+
<%= link_to image_tag('control_play_blue.png',
|
148
|
+
class: 'action',
|
149
|
+
title: "Re-enqueue one instance of job #{@historical_job.id}"),
|
150
|
+
"#", params %>
|
151
|
+
</td>
|
140
152
|
<% end %>
|
141
153
|
</tbody>
|
142
154
|
</table>
|
@@ -163,8 +175,12 @@
|
|
163
175
|
</tbody>
|
164
176
|
</table>
|
165
177
|
</br>
|
166
|
-
<%= render partial: 'naf/log_viewer/log_layout', locals: {
|
167
|
-
|
178
|
+
<%= render partial: 'naf/log_viewer/log_layout', locals: {
|
179
|
+
record_id: @historical_job.id,
|
180
|
+
record_type: 'job',
|
181
|
+
runner_name: @logical_job.runner,
|
182
|
+
server: @logical_job.started_on_machine.try(:server_name),
|
183
|
+
status: @logical_job.status } %>
|
168
184
|
</div>
|
169
185
|
<% end %>
|
170
186
|
|
@@ -177,30 +193,5 @@
|
|
177
193
|
logs_url: "#{http_protocol}#{@logical_job.runner}#{naf.logs_log_parsers_path}",
|
178
194
|
record_type: 'job' } %>
|
179
195
|
|
180
|
-
|
181
|
-
|
182
|
-
jQuery(document).ready(function () {
|
183
|
-
jQuery(document).delegate('.terminate', "click", function(){
|
184
|
-
var answer = confirm("You are terminating this job. Are you sure you want to do this?");
|
185
|
-
if (!answer) {
|
186
|
-
return false;
|
187
|
-
}
|
188
|
-
var id = <%= @historical_job.id %>;
|
189
|
-
jQuery.ajax({
|
190
|
-
url: id,
|
191
|
-
type:'POST',
|
192
|
-
dataType:'json',
|
193
|
-
data:{ "historical_job[request_to_terminate]": 1, "historical_job_id": id, "_method": "put" },
|
194
|
-
success:function (data) {
|
195
|
-
if (data.success) {
|
196
|
-
var title = data.title ? data.title : data.command
|
197
|
-
jQuery("<p id='notice'>A Job " + title + " was terminated!</p>").
|
198
|
-
appendTo('#flash_message').slideDown().delay(5000).slideUp();
|
199
|
-
setTimeout('window.location.reload()', 5600);
|
200
|
-
}
|
201
|
-
}
|
202
|
-
});
|
203
|
-
});
|
204
|
-
});
|
205
|
-
</script>
|
206
|
-
<% end %>
|
196
|
+
<!-- This partial controls terminate and re-enqueue links -->
|
197
|
+
<% render partial: 'button_control', locals: { historical_job_id: @historical_job.id } %>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<% style_text = "vertical-align: bottom;" %>
|
2
|
+
<% if status == 'Queued' || server.blank?
|
3
|
+
style_text << " display: none;"
|
4
|
+
end %>
|
5
|
+
<%= button_tag(style: "#{style_text}") do
|
6
|
+
link_to 'Download',
|
7
|
+
link_path,
|
8
|
+
style: "color: black;"
|
9
|
+
end
|
10
|
+
%>
|
11
|
+
</button>
|
@@ -48,6 +48,9 @@
|
|
48
48
|
</br>
|
49
49
|
|
50
50
|
<%= submit_tag("Search the logs", id: 'log_search_submit') %>
|
51
|
+
<%= render partial: 'job_log_download_button', locals: { server: @job.started_on_machine.try(:server_name),
|
52
|
+
status: logical_job.status,
|
53
|
+
link_path: "#{http_protocol}#{logical_job.runner}#{naf.download_log_parsers_path}?record_id=#{@job.id}&record_type=job" } %>
|
51
54
|
|
52
55
|
<%= link_to 'Back to Job', { controller: 'historical_jobs', action: 'show', id: @job.id } %>
|
53
56
|
</div>
|
@@ -129,7 +129,7 @@
|
|
129
129
|
jQuery('#stdout').text('')
|
130
130
|
jQuery('#stdout').append(logs);
|
131
131
|
if(jQuery('#stdout').text() == '') {
|
132
|
-
logs = "No logs were found for this search query
|
132
|
+
logs = "<pre style='display: inline; word-wrap: break-word;'>No logs were found for this search query!</pre><br>";
|
133
133
|
setAutoScrollOff();
|
134
134
|
}
|
135
135
|
jQuery("#stdout").scrollTop(jQuery('#stdout')[0].scrollHeight);
|
@@ -138,7 +138,7 @@
|
|
138
138
|
}
|
139
139
|
else{
|
140
140
|
if(logs == '' && jQuery('#stdout')[0].children.length == 0) {
|
141
|
-
logs = "
|
141
|
+
logs = "<span><pre style='display: inline; word-wrap: break-word;'>No logs were found!</pre><br></span>";
|
142
142
|
setAutoScrollOff();
|
143
143
|
}
|
144
144
|
|
@@ -165,10 +165,10 @@
|
|
165
165
|
}
|
166
166
|
},
|
167
167
|
error: function(response) {
|
168
|
-
message = '
|
168
|
+
message = '<span><pre style="display: inline; word-wrap: break-word;">Failed to retrieve ' + '<%= record_type %>' + '(' +
|
169
169
|
'<%= record_id %>' + ') logs from ' + '<%= logs_url %>'.match(/^https?\:\/\/([^\/?#]+)/).pop() + '. Please refer to ' +
|
170
170
|
'Naf FAQs on the' + ' wiki'.link('https://github.com/fiksu/naf/wiki/Frequently-Asked-Questions') +
|
171
|
-
' for further information
|
171
|
+
' for further information.</pre><br></span>';
|
172
172
|
|
173
173
|
jQuery('#stdout').prepend(message);
|
174
174
|
}
|
@@ -47,6 +47,11 @@
|
|
47
47
|
<%= link_to 'Auto Scroll (ON)', '#', id: :auto_scroll %>
|
48
48
|
</br></br>
|
49
49
|
<%= submit_tag("Search the logs", id: 'log_search_submit') %>
|
50
|
+
<% if record_type == 'job' %>
|
51
|
+
<%= render partial: 'naf/log_viewer/job_log_download_button', locals: {
|
52
|
+
server: server, status: status,
|
53
|
+
link_path: "#{http_protocol}#{runner_name}#{naf.download_log_parsers_path}?record_id=#{record_id}&record_type=job" } %>
|
54
|
+
<% end %>
|
50
55
|
<%= link_to 'Full Screen',
|
51
56
|
{ controller: 'log_viewer', action: 'index', record_id: record_id, record_type: record_type },
|
52
57
|
{ class: 'full_screen' } %>
|
data/config/routes.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
Naf::Engine.routes.draw do
|
2
2
|
resources :historical_jobs, except: [:edit] do
|
3
|
+
collection do
|
4
|
+
post :reenqueue
|
5
|
+
end
|
3
6
|
resources :historical_job_affinity_tabs, except: [:destroy]
|
4
7
|
end
|
5
8
|
|
@@ -31,6 +34,7 @@ Naf::Engine.routes.draw do
|
|
31
34
|
resources :log_parsers, only: [] do
|
32
35
|
collection do
|
33
36
|
get :logs
|
37
|
+
get :download
|
34
38
|
end
|
35
39
|
end
|
36
40
|
resources :status, only: [:index]
|
data/lib/naf.rb
CHANGED
@@ -45,6 +45,14 @@ module Naf
|
|
45
45
|
configuration.simple_cluster_authenticator_cookie_expiration_time
|
46
46
|
end
|
47
47
|
|
48
|
+
def metric_tags
|
49
|
+
configuration.metric_tags
|
50
|
+
end
|
51
|
+
|
52
|
+
def metric_send_delay
|
53
|
+
configuration.metric_send_delay
|
54
|
+
end
|
55
|
+
|
48
56
|
def using_another_database?
|
49
57
|
model_class != ActiveRecord::Base
|
50
58
|
end
|
data/lib/naf/configuration.rb
CHANGED
@@ -8,7 +8,9 @@ module Naf
|
|
8
8
|
:layout,
|
9
9
|
:default_page_options,
|
10
10
|
:api_domain_cookie_name,
|
11
|
-
:simple_cluster_authenticator_cookie_expiration_time
|
11
|
+
:simple_cluster_authenticator_cookie_expiration_time,
|
12
|
+
:metric_tags,
|
13
|
+
:metric_send_delay
|
12
14
|
|
13
15
|
def initialize
|
14
16
|
@model_class = "::ActiveRecord::Base"
|
@@ -19,6 +21,8 @@ module Naf
|
|
19
21
|
@api_controller_class = "Naf::ApiSimpleClusterAuthenticatorApplicationController"
|
20
22
|
@simple_cluster_authenticator_cookie_expiration_time = 1.week
|
21
23
|
@api_domain_cookie_name = "naf_#{Rails.application.class.parent.name.underscore}"
|
24
|
+
@metric_tags = ["#{Rails.env}"]
|
25
|
+
@metric_send_delay = 120
|
22
26
|
end
|
23
27
|
|
24
28
|
end
|
data/lib/naf/version.rb
CHANGED
data/naf.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.name = 'naf'
|
9
9
|
s.version = Naf::VERSION
|
10
10
|
s.license = 'New BSD License'
|
11
|
-
s.date = '2014-
|
11
|
+
s.date = '2014-07-08'
|
12
12
|
s.summary = 'Creates infrastructure for a customizable and robust Postgres-backed script scheduling/running'
|
13
13
|
s.description = 'A cloud based distributed cron, application framework and operations console. Naf works as a distributed script running ' +
|
14
14
|
'system that provides scheduling, logging, alarming, machine redundancy, and the ability to set constraint during script execution'
|
@@ -24,8 +24,11 @@ Gem::Specification.new do |s|
|
|
24
24
|
s.add_dependency 'jquery-rails'
|
25
25
|
s.add_dependency 'will_paginate'
|
26
26
|
s.add_dependency 'facter', '~> 1.7.5'
|
27
|
+
s.add_dependency 'aws-sdk', '>= 1.1.0'
|
28
|
+
s.add_dependency 'yajl-ruby', '>= 1.1.0'
|
29
|
+
s.add_dependency 'dogstatsd-ruby', '>= 1.2.0'
|
27
30
|
s.add_development_dependency 'pg'
|
28
|
-
s.add_development_dependency 'rspec-rails'
|
31
|
+
s.add_development_dependency 'rspec-rails', '~> 2.14.0'
|
29
32
|
s.add_development_dependency 'factory_girl_rails', '~> 4.0.0'
|
30
33
|
s.add_development_dependency 'awesome_print'
|
31
34
|
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Naf
|
4
|
+
|
5
|
+
describe LogParsersController do
|
6
|
+
|
7
|
+
before do
|
8
|
+
Logical::Naf::LogParser::JobDownloader.any_instance.stub(:logs_for_download).and_return("Test Log String")
|
9
|
+
end
|
10
|
+
|
11
|
+
it "raises no exceptions" do
|
12
|
+
assert_nothing_raised do
|
13
|
+
get :download, {'record_id' => 3}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "has a successful response" do
|
18
|
+
get :download, {'record_id' => 3}
|
19
|
+
assert_response(:success)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "returns the correct string" do
|
23
|
+
get :download, {'record_id' => 3}
|
24
|
+
expect(response.body).to eql("Test Log String\n")
|
25
|
+
end
|
26
|
+
|
27
|
+
it "has the right disposition of attachment" do
|
28
|
+
get :download, {'record_id' => 3}
|
29
|
+
disposition = response.header["Content-Disposition"]
|
30
|
+
expect(disposition.include?("attachment")).to be_true
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Logical
|
4
|
+
module Naf
|
5
|
+
|
6
|
+
describe ApplicationSchedule do
|
7
|
+
|
8
|
+
describe '#exact_time_of_day' do
|
9
|
+
|
10
|
+
#----------------
|
11
|
+
# *** Methods ***
|
12
|
+
#++++++++++++++++
|
13
|
+
|
14
|
+
def update_schedule(run_interval)
|
15
|
+
schedule.run_interval = run_interval
|
16
|
+
schedule.save
|
17
|
+
|
18
|
+
::Logical::Naf::ApplicationSchedule.new(schedule)
|
19
|
+
end
|
20
|
+
|
21
|
+
#------------------------
|
22
|
+
# *** Shared Examples ***
|
23
|
+
#++++++++++++++++++++++++
|
24
|
+
|
25
|
+
shared_examples 'displays the hour correctly' do |run_interval, time|
|
26
|
+
it { update_schedule(run_interval).exact_time_of_day.should == time }
|
27
|
+
end
|
28
|
+
|
29
|
+
let!(:schedule) { FactoryGirl.create(:schedule_base) }
|
30
|
+
|
31
|
+
it_should_behave_like 'displays the hour correctly', 10, '12:10 AM'
|
32
|
+
it_should_behave_like 'displays the hour correctly', 480, '08:00 AM'
|
33
|
+
it_should_behave_like 'displays the hour correctly', 2880, '12:00 AM'
|
34
|
+
it_should_behave_like 'displays the hour correctly', 20160, '12:00 AM'
|
35
|
+
it_should_behave_like 'displays the hour correctly', 46080, '12:00 AM'
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -32,6 +32,11 @@ module Logical::Naf::ConstructionZone
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
before do
|
36
|
+
::Naf::HistoricalJob.delete_all
|
37
|
+
::Naf::ApplicationType.all
|
38
|
+
end
|
39
|
+
|
35
40
|
describe '#enqueue_application' do
|
36
41
|
let(:application) { FactoryGirl.create(:application) }
|
37
42
|
let(:prereq) { FactoryGirl.create(:job) }
|
@@ -44,13 +44,16 @@ module Logical::Naf::ConstructionZone
|
|
44
44
|
describe 'run group restriction is set to limited per machine' do
|
45
45
|
let!(:machine) { FactoryGirl.create(:machine) }
|
46
46
|
let(:historical_job) { FactoryGirl.create(:job, application_run_group_name: 'test') }
|
47
|
-
let(:tab) { FactoryGirl.create(:machine_job_affinity_tab, historical_job_id: historical_job.id) }
|
47
|
+
let!(:tab) { FactoryGirl.create(:machine_job_affinity_tab, historical_job_id: historical_job.id) }
|
48
48
|
|
49
49
|
before do
|
50
|
-
FactoryGirl.create(:queued_job, application_run_group_name: 'test',
|
50
|
+
FactoryGirl.create(:queued_job, application_run_group_name: 'test',
|
51
|
+
id: historical_job.id,
|
52
|
+
historical_job: historical_job)
|
51
53
|
FactoryGirl.create(:running_job_base, application_run_group_name: 'test',
|
52
54
|
started_on_machine_id: machine.id,
|
53
|
-
|
55
|
+
historical_job: historical_job,
|
56
|
+
id: historical_job.id)
|
54
57
|
end
|
55
58
|
|
56
59
|
it 'return false when application does not have affinity associated with machine' do
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Logical
|
4
|
+
module Naf
|
5
|
+
module LogParser
|
6
|
+
describe JobDownloader do
|
7
|
+
# Create a test file, making sure to not overwrite a current file.
|
8
|
+
|
9
|
+
let!(:test_record_id) { 3 }
|
10
|
+
let!(:test_file_path) { "#{::Naf::PREFIX_PATH}/#{::Naf.schema_name}/jobs/#{test_record_id}" }
|
11
|
+
let!(:test_file_name) { "1_20140613_161535.json" }
|
12
|
+
let!(:test_file_text) { "{\n" +
|
13
|
+
" \"line_number\": 1,\n" +
|
14
|
+
" \"output_time\": \"2014-06-13 16:15:35.689\",\n" +
|
15
|
+
" \"message\": \"140613 12:15:35.689 pid=6020 jid=3 Process::Naf::LogArchiver INFO Starting to save files to s3...\"\n" +
|
16
|
+
"}" }
|
17
|
+
let!(:test_file_output) { "1 2014-06-13 16:15:35.689: 140613 12:15:35.689 pid=6020 jid=3 Process::Naf::LogArchiver INFO Starting to save files to s3...\n" }
|
18
|
+
let!(:segments_to_reset) { {} }
|
19
|
+
let!(:file_preserved) { false }
|
20
|
+
|
21
|
+
before() do
|
22
|
+
# Create a file/directory for example log. If directory exists, move it and save it
|
23
|
+
segments_to_reset = {}
|
24
|
+
total_path = ""
|
25
|
+
file_preserved = false
|
26
|
+
|
27
|
+
test_file_path.split("/").each do |segment|
|
28
|
+
unless segment == ""
|
29
|
+
segments_to_reset[segment] = false
|
30
|
+
unless File.exists?(total_path + segment + "/")
|
31
|
+
Dir.mkdir(total_path + segment + "/")
|
32
|
+
segments_to_reset[segment] = true
|
33
|
+
end
|
34
|
+
total_path += segment + "/"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
if File.exists?("#{test_file_path}/#{test_file_name}")
|
39
|
+
FileUtils.mv("#{test_file_path}/#{test_file_name}", "#{test_file_path}/#{test_file_name}-preserving")
|
40
|
+
file_preserved = true
|
41
|
+
end
|
42
|
+
|
43
|
+
File.open("#{test_file_path}/#{test_file_name}", 'w') { |file| file.write(test_file_text) }
|
44
|
+
end
|
45
|
+
|
46
|
+
after() do
|
47
|
+
# Delete the example log file. If a directory was saved before, move it back
|
48
|
+
File.delete("#{test_file_path}/#{test_file_name}")
|
49
|
+
|
50
|
+
if file_preserved
|
51
|
+
FileUtils.mv("#{test_file_path}/#{test_file_name}-preserving", "#{test_file_path}/#{test_file_name}")
|
52
|
+
end
|
53
|
+
|
54
|
+
current_path = test_file_path
|
55
|
+
test_file_path.split("/").reverse_each do |segment|
|
56
|
+
if segments_to_reset[segment]
|
57
|
+
Dir.rmdir(current_path)
|
58
|
+
current_path = current_path[0..-(segment.size + 2)]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
it "returns the correct log" do
|
65
|
+
job_log_downloader = JobDownloader.new({ 'record_id' => test_record_id })
|
66
|
+
job_log_downloader.logs_for_download.should eql(test_file_output)
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Logical
|
4
|
+
module Naf
|
5
|
+
module JobStatuses
|
6
|
+
|
7
|
+
describe Errored do
|
8
|
+
|
9
|
+
context "no conditions" do
|
10
|
+
|
11
|
+
let!(:conditions) { "" }
|
12
|
+
|
13
|
+
it "returns executable query" do
|
14
|
+
expect { ActiveRecord::Base.connection.execute(Errored.all(conditions)) }.to_not raise_error
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
context "with conditions" do
|
20
|
+
|
21
|
+
let!(:conditions) { "TEST STRING" }
|
22
|
+
|
23
|
+
it "adds conditions to returned sql string" do
|
24
|
+
expect(Errored.all(conditions).include?(conditions)).to be_true
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Logical
|
4
|
+
module Naf
|
5
|
+
module JobStatuses
|
6
|
+
|
7
|
+
describe FinishedLessMinute do
|
8
|
+
|
9
|
+
context "no conditions" do
|
10
|
+
|
11
|
+
let!(:conditions) { "" }
|
12
|
+
|
13
|
+
it "returns executable query" do
|
14
|
+
expect { ActiveRecord::Base.connection.execute(FinishedLessMinute.all(conditions)) }.to_not raise_error
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
context "with conditions" do
|
20
|
+
|
21
|
+
let!(:conditions) { "TEST STRING" }
|
22
|
+
|
23
|
+
it "adds conditions to returned sql string" do
|
24
|
+
expect(FinishedLessMinute.all(conditions).include?(conditions)).to be_true
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|