marty 2.3.15 → 2.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.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/app/components/marty/api_auth_view.rb +27 -4
- data/app/components/marty/api_config_view.rb +27 -4
- data/app/components/marty/extras/layout.rb +4 -7
- data/app/components/marty/form.rb +8 -0
- data/app/components/marty/grid.rb +45 -19
- data/app/components/marty/main_auth_app.rb +12 -11
- data/app/controllers/marty/rpc_controller.rb +63 -150
- data/app/models/marty/api_auth.rb +86 -14
- data/app/models/marty/api_config.rb +11 -6
- data/app/models/marty/delorean_rule.rb +3 -2
- data/config/routes.rb +1 -1
- data/db/migrate/501_add_api_class_to_marty_api_config.rb +6 -0
- data/db/migrate/502_add_parameters_to_marty_api_auth.rb +5 -0
- data/lib/marty/util.rb +0 -15
- data/lib/marty/version.rb +1 -1
- data/other/marty/api/base.rb +207 -0
- data/other/marty/diagnostic/aws/ec2_instance.rb +12 -87
- data/other/marty/diagnostic/environment_variables.rb +1 -1
- data/spec/controllers/job_controller_spec.rb +1 -1
- data/spec/dummy/app/components/gemini/xyz_rule_view.rb +1 -0
- data/spec/dummy/config/application.rb +1 -0
- data/spec/features/enum_spec.rb +35 -100
- data/spec/features/log_view_spec.rb +5 -5
- data/spec/features/rule_spec.rb +30 -30
- data/spec/features/user_view_spec.rb +0 -2
- data/spec/lib/logger_spec.rb +1 -1
- data/spec/models/api_auth_spec.rb +33 -12
- data/spec/models/event_spec.rb +1 -1
- data/spec/models/promise_spec.rb +1 -1
- data/spec/models/user_spec.rb +6 -6
- data/spec/spec_helper.rb +69 -9
- data/spec/support/{shared_connection_db_helpers.rb → clean_db_helpers.rb} +2 -2
- data/spec/support/delayed_job_helpers.rb +1 -1
- data/spec/support/{users.rb → integration_helpers.rb} +9 -11
- data/spec/support/{setup.rb → spec_setup.rb} +6 -19
- data/spec/support/user_helpers.rb +12 -0
- metadata +10 -21
- data/spec/dummy/app/assets/client/application.css +0 -13
- data/spec/dummy/app/assets/client/application.js +0 -15
- data/spec/support/chromedriver.rb +0 -41
- data/spec/support/components/netzke_combobox.rb +0 -57
- data/spec/support/components/netzke_grid.rb +0 -356
- data/spec/support/custom_matchers.rb +0 -18
- data/spec/support/custom_selectors.rb +0 -49
- data/spec/support/download_helper.rb +0 -52
- data/spec/support/helper.rb +0 -20
- data/spec/support/netzke.rb +0 -306
- data/spec/support/performance_helper.rb +0 -26
- data/spec/support/post_run_logger.rb +0 -32
- data/spec/support/shared_connection.rb +0 -31
- data/spec/support/structure_compare.rb +0 -62
- data/spec/support/suite.rb +0 -27
@@ -1,356 +0,0 @@
|
|
1
|
-
require 'capybara/dsl'
|
2
|
-
require 'rspec/matchers'
|
3
|
-
require Pathname.new(__FILE__).parent.parent.to_s + '/netzke'
|
4
|
-
|
5
|
-
module Marty; module RSpec; module Components
|
6
|
-
class NetzkeGrid
|
7
|
-
include Netzke
|
8
|
-
include Capybara::DSL
|
9
|
-
#include RSpec::Matchers
|
10
|
-
|
11
|
-
attr_reader :name, :grid
|
12
|
-
|
13
|
-
def initialize(name, c_type)
|
14
|
-
# for now, also allows treepanel
|
15
|
-
@name = name
|
16
|
-
if /^\d+$/.match(name)
|
17
|
-
@grid = ext_find(c_type, nil, name)
|
18
|
-
else
|
19
|
-
@grid = ext_find(ext_arg(c_type, name: name))
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def id
|
24
|
-
res = run_js <<-JS
|
25
|
-
var c = #{grid};
|
26
|
-
return c.view.id;
|
27
|
-
JS
|
28
|
-
res
|
29
|
-
end
|
30
|
-
|
31
|
-
def row_count
|
32
|
-
res = run_js <<-JS
|
33
|
-
return #{grid}.getStore().getTotalCount();
|
34
|
-
JS
|
35
|
-
res.to_i
|
36
|
-
end
|
37
|
-
|
38
|
-
def page_size
|
39
|
-
res = run_js <<-JS
|
40
|
-
return #{grid}.getStore().pageSize();
|
41
|
-
JS
|
42
|
-
res.to_i
|
43
|
-
end
|
44
|
-
|
45
|
-
alias :row_total :row_count
|
46
|
-
|
47
|
-
def row_modified_count
|
48
|
-
res = run_js <<-JS
|
49
|
-
return #{grid}.getStore().getUpdatedRecords().length;
|
50
|
-
JS
|
51
|
-
res.to_i
|
52
|
-
end
|
53
|
-
|
54
|
-
def data_desc row
|
55
|
-
res = run_js <<-JS
|
56
|
-
var r = #{grid}.getStore().getAt(#{row.to_i-1});
|
57
|
-
return r.data.desc
|
58
|
-
JS
|
59
|
-
res.gsub(/<.*?>/, '')
|
60
|
-
end
|
61
|
-
|
62
|
-
def click_col col
|
63
|
-
el = run_js <<-JS
|
64
|
-
#{ext_var(grid, 'grid')}
|
65
|
-
return #{ext_find(ext_arg('gridcolumn', text: col), 'grid')}.id
|
66
|
-
JS
|
67
|
-
|
68
|
-
find("#" + el).click
|
69
|
-
end
|
70
|
-
|
71
|
-
def get_col_vals(col, cnt=row_count, init=0)
|
72
|
-
# NOTE: does not validate the # of rows
|
73
|
-
run_js <<-JS
|
74
|
-
var result = [];
|
75
|
-
for (var i = #{init}; i < #{init.to_i + cnt.to_i}; i++) {
|
76
|
-
#{ext_cell_val('i', col, grid)}
|
77
|
-
if(value instanceof Date){
|
78
|
-
result.push(value.toISOString().substring(0,value.toISOString().indexOf('T')));
|
79
|
-
} else {
|
80
|
-
result.push(value);
|
81
|
-
};
|
82
|
-
};
|
83
|
-
return result;
|
84
|
-
JS
|
85
|
-
end
|
86
|
-
|
87
|
-
def validate_col_vals(col, val, cnt, init=0)
|
88
|
-
run_js <<-JS
|
89
|
-
for (var i = #{init}; i < #{init.to_i + cnt.to_i}; i++) {
|
90
|
-
#{ext_cell_val('i', col, grid)}
|
91
|
-
if (value != #{val}) { return false };
|
92
|
-
};
|
93
|
-
return true;
|
94
|
-
JS
|
95
|
-
end
|
96
|
-
|
97
|
-
def cell_value(row, col)
|
98
|
-
run_js <<-JS
|
99
|
-
#{ext_cell_val(row.to_i - 1, col, grid)}
|
100
|
-
return value;
|
101
|
-
JS
|
102
|
-
end
|
103
|
-
|
104
|
-
def select_row(row, click_after=true)
|
105
|
-
resid = run_js(<<-JS, 10.0)
|
106
|
-
#{ext_var(grid, 'grid')}
|
107
|
-
grid.getSelectionModel().select(#{row.to_i-1});
|
108
|
-
return grid.getView().getNode(#{row.to_i-1}).id;
|
109
|
-
JS
|
110
|
-
el = find_by_id(resid)
|
111
|
-
el.click if click_after
|
112
|
-
wait_for_ajax
|
113
|
-
return el
|
114
|
-
end
|
115
|
-
|
116
|
-
def set_row_vals row, fields
|
117
|
-
js_set_fields = fields.each_pair.map do |k,v|
|
118
|
-
"r.set('#{k}', '#{v}');"
|
119
|
-
end.join
|
120
|
-
|
121
|
-
run_js <<-JS
|
122
|
-
#{ext_var(ext_row(row.to_i - 1, grid), 'r')}
|
123
|
-
#{js_set_fields}
|
124
|
-
JS
|
125
|
-
end
|
126
|
-
|
127
|
-
def get_row_vals row, fields=nil
|
128
|
-
res = run_js <<-JS
|
129
|
-
#{ext_var(grid, 'grid')}
|
130
|
-
return Ext.encode(#{ext_row(row.to_i - 1, 'grid')}.data);
|
131
|
-
JS
|
132
|
-
temp = JSON.parse(res)
|
133
|
-
parsed = temp.merge(temp.delete('association_values') || {})
|
134
|
-
fields ? fields.each_with_object({}).each{|k,h| h[k] = parsed[k]} :
|
135
|
-
parsed
|
136
|
-
end
|
137
|
-
|
138
|
-
def sorted_by? col, direction = 'asc'
|
139
|
-
run_js <<-JS
|
140
|
-
#{ext_var(grid, 'grid')}
|
141
|
-
#{ext_var(ext_col(col, 'grid'), 'col')}
|
142
|
-
var colValues = [];
|
143
|
-
|
144
|
-
grid.getStore().each(function(r){
|
145
|
-
var val = col.assoc ? r.get('association_values')['#{col}'] :
|
146
|
-
r.get('#{col}');
|
147
|
-
if (val) colValues.#{direction == 'asc' ? 'push' : 'unshift'}(val);
|
148
|
-
});
|
149
|
-
|
150
|
-
return colValues.toString() === Ext.Array.sort(colValues).toString();
|
151
|
-
JS
|
152
|
-
end
|
153
|
-
|
154
|
-
def grid_combobox_values(row, field)
|
155
|
-
run_js <<-JS
|
156
|
-
#{start_edit_combobox(row, field)}
|
157
|
-
JS
|
158
|
-
|
159
|
-
# hacky: delay for combobox to render, assumes combobox is not empty
|
160
|
-
run_js <<-JS
|
161
|
-
#{ext_var(grid, 'grid')}
|
162
|
-
#{ext_var(ext_netzkecombo(field), 'combo')}
|
163
|
-
var r = [];
|
164
|
-
#{ext_var(ext_celleditor, 'editor')}
|
165
|
-
var store = combo.getStore();
|
166
|
-
|
167
|
-
// force a retry if the store is still loading
|
168
|
-
if (store.loading == true) {
|
169
|
-
now = new Date().getTime();
|
170
|
-
while(new Date().getTime() < now + 100) { }
|
171
|
-
return false;
|
172
|
-
}
|
173
|
-
|
174
|
-
for(var i = 0; i < store.getCount(); i++) {
|
175
|
-
r.push(store.getAt(i).get('text'));
|
176
|
-
};
|
177
|
-
|
178
|
-
editor.completeEdit();
|
179
|
-
return r;
|
180
|
-
JS
|
181
|
-
end
|
182
|
-
|
183
|
-
def get_combobox_val(index, row, field)
|
184
|
-
run_js <<-JS
|
185
|
-
#{start_edit_combobox(row, field)}
|
186
|
-
JS
|
187
|
-
|
188
|
-
run_js <<-JS
|
189
|
-
#{ext_var(grid, 'grid')}
|
190
|
-
#{ext_var(ext_netzkecombo(field), 'combo')}
|
191
|
-
#{ext_var(ext_celleditor, 'editor')}
|
192
|
-
var val = combo.getStore().getAt(#{index}).get('text');
|
193
|
-
editor.completeEdit();
|
194
|
-
return val;
|
195
|
-
JS
|
196
|
-
end
|
197
|
-
|
198
|
-
def start_edit_grid_combobox(row, field)
|
199
|
-
<<-JS
|
200
|
-
#{ext_var(grid, 'grid')}
|
201
|
-
#{ext_var(ext_netzkecombo(field), 'combo')}
|
202
|
-
#{ext_var(ext_celleditor, 'editor')}
|
203
|
-
|
204
|
-
editor.startEditByPosition({ row:#{row.to_i-1},
|
205
|
-
column:grid.headerCt.items.findIndex('name', '#{field}') });
|
206
|
-
|
207
|
-
var now = new Date().getTime();
|
208
|
-
while(new Date().getTime() < now + 500) { }
|
209
|
-
|
210
|
-
combo.onTriggerClick();
|
211
|
-
JS
|
212
|
-
end
|
213
|
-
|
214
|
-
def id_of_edit_field(row, field)
|
215
|
-
res = run_js <<-JS
|
216
|
-
#{ext_var(grid, 'grid')}
|
217
|
-
#{ext_var(ext_celleditor, 'editor')}
|
218
|
-
|
219
|
-
editor.startEditByPosition({ row:#{row.to_i-1},
|
220
|
-
column:grid.headerCt.items.findIndex('name', '#{field}') });
|
221
|
-
return editor.activeEditor.field.inputId;
|
222
|
-
JS
|
223
|
-
res
|
224
|
-
end
|
225
|
-
|
226
|
-
def end_edit(row, field)
|
227
|
-
run_js <<-JS
|
228
|
-
#{ext_var(grid, 'grid')}
|
229
|
-
#{ext_var(ext_celleditor, 'editor')}
|
230
|
-
editor.completeEdit();
|
231
|
-
return true;
|
232
|
-
JS
|
233
|
-
end
|
234
|
-
|
235
|
-
def id_of_checkbox(row, field)
|
236
|
-
res = run_js <<-JS
|
237
|
-
#{ext_var(grid, 'grid')}
|
238
|
-
#{ext_var(ext_celleditor, 'editor')}
|
239
|
-
|
240
|
-
editor.startEditByPosition({ row:#{row.to_i-1},
|
241
|
-
column:grid.headerCt.items.findIndex('name', '#{field}') });
|
242
|
-
return editor.activeEditor.field.getItemId();
|
243
|
-
JS
|
244
|
-
res
|
245
|
-
end
|
246
|
-
|
247
|
-
############################################################################
|
248
|
-
# grid combobox helpers
|
249
|
-
############################################################################
|
250
|
-
|
251
|
-
def select_combobox(selection, row, field)
|
252
|
-
run_js <<-JS
|
253
|
-
#{start_edit_combobox(row, field)}
|
254
|
-
|
255
|
-
rec = combo.findRecordByDisplay('#{selection}');
|
256
|
-
if (rec == false) { return false; }
|
257
|
-
combo.setValue(rec);
|
258
|
-
combo.onTriggerClick();
|
259
|
-
editor.completeEdit();
|
260
|
-
return true
|
261
|
-
JS
|
262
|
-
end
|
263
|
-
|
264
|
-
def select_combobox_enum(selection, row, field)
|
265
|
-
run_js <<-JS
|
266
|
-
#{start_edit_combobox_enum(row, field)}
|
267
|
-
|
268
|
-
rec = combo.findRecordByDisplay('#{selection}');
|
269
|
-
if (rec == false) { return false; }
|
270
|
-
combo.setValue(rec);
|
271
|
-
editor.completeEdit();
|
272
|
-
return true
|
273
|
-
JS
|
274
|
-
end
|
275
|
-
|
276
|
-
def combobox_values(row, field)
|
277
|
-
run_js <<-JS
|
278
|
-
#{start_edit_combobox(row, field)}
|
279
|
-
JS
|
280
|
-
|
281
|
-
# hacky: delay for combobox to render, assumes that the combobox is not empty
|
282
|
-
run_js <<-JS
|
283
|
-
#{ext_var(grid, 'grid')}
|
284
|
-
#{ext_var(ext_netzkecombo(field), 'combo')}
|
285
|
-
var r = [];
|
286
|
-
#{ext_var(ext_celleditor, 'editor')}
|
287
|
-
var store = combo.getStore();
|
288
|
-
|
289
|
-
// force a retry if the store is still loading
|
290
|
-
if (store.loading == true) {
|
291
|
-
now = new Date().getTime();
|
292
|
-
while(new Date().getTime() < now + 100) { }
|
293
|
-
return false;
|
294
|
-
}
|
295
|
-
|
296
|
-
for(var i = 0; i < store.getCount(); i++) {
|
297
|
-
r.push(store.getAt(i).get('text'));
|
298
|
-
};
|
299
|
-
|
300
|
-
editor.completeEdit();
|
301
|
-
return r;
|
302
|
-
JS
|
303
|
-
end
|
304
|
-
|
305
|
-
def get_combobox_val(index, row, field)
|
306
|
-
run_js <<-JS
|
307
|
-
#{start_edit_combobox(row, field)}
|
308
|
-
JS
|
309
|
-
|
310
|
-
run_js <<-JS
|
311
|
-
#{ext_var(grid, 'grid')}
|
312
|
-
#{ext_var(ext_netzkecombo(field), 'combo')}
|
313
|
-
#{ext_var(ext_celleditor, 'editor')}
|
314
|
-
var val = combo.getStore().getAt(#{index}).get('text');
|
315
|
-
editor.completeEdit();
|
316
|
-
return val;
|
317
|
-
JS
|
318
|
-
end
|
319
|
-
|
320
|
-
def start_edit_combobox(row, field)
|
321
|
-
<<-JS
|
322
|
-
#{ext_var(grid, 'grid')}
|
323
|
-
#{ext_var(ext_netzkecombo(field), 'combo')}
|
324
|
-
#{ext_var(ext_celleditor, 'editor')}
|
325
|
-
|
326
|
-
editor.startEditByPosition({ row:#{row.to_i-1},
|
327
|
-
column:grid.headerCt.items.findIndex('name', '#{field}') });
|
328
|
-
|
329
|
-
var now = new Date().getTime();
|
330
|
-
while(new Date().getTime() < now + 500) { }
|
331
|
-
|
332
|
-
combo.onTriggerClick();
|
333
|
-
JS
|
334
|
-
end
|
335
|
-
|
336
|
-
def start_edit_combobox_enum(row, field)
|
337
|
-
<<-JS
|
338
|
-
#{ext_var(grid, 'grid')}
|
339
|
-
#{ext_combo(field, 'combo')}
|
340
|
-
#{ext_var(ext_celleditor, 'editor')}
|
341
|
-
|
342
|
-
editor.startEditByPosition({ row:#{row.to_i-1},
|
343
|
-
column:grid.headerCt.items.findIndex('name', '#{field}') });
|
344
|
-
JS
|
345
|
-
end
|
346
|
-
|
347
|
-
def end_edit(row, field)
|
348
|
-
run_js <<-JS
|
349
|
-
#{ext_var(grid, 'grid')}
|
350
|
-
#{ext_var(ext_celleditor, 'editor')}
|
351
|
-
editor.completeEdit();
|
352
|
-
return true;
|
353
|
-
JS
|
354
|
-
end
|
355
|
-
end
|
356
|
-
end end end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'rspec'
|
2
|
-
|
3
|
-
RSpec::Matchers.define :netzke_include do |expected|
|
4
|
-
match do |actual|
|
5
|
-
parsed_values = actual.each_with_object({}) do | (k, v), h |
|
6
|
-
h[k] = v == "False" ? false : v
|
7
|
-
end
|
8
|
-
expect(parsed_values).to include(expected.stringify_keys)
|
9
|
-
end
|
10
|
-
|
11
|
-
diffable
|
12
|
-
end
|
13
|
-
|
14
|
-
RSpec::Matchers.define :match_fuzzily do |expected|
|
15
|
-
msg = nil
|
16
|
-
match { |actual| !(msg = struct_compare(actual, expected)) }
|
17
|
-
failure_message { |_| msg }
|
18
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
Capybara.add_selector(:gridpanel) do
|
2
|
-
xpath do |name|
|
3
|
-
".//div[contains(@id, '#{name}')][not(contains(@id, 'splitter'))] | "\
|
4
|
-
".//div[contains(@id, '#{name.camelize(:lower)}')]"\
|
5
|
-
"[not(contains(@id, 'splitter'))]"
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
Capybara.add_selector(:msg) do
|
10
|
-
xpath do
|
11
|
-
"//div[@id='msg-div']"
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
Capybara.add_selector(:body) do
|
16
|
-
xpath do
|
17
|
-
".//div[@data-ref='body']"
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
Capybara.add_selector(:input) do
|
22
|
-
xpath do |name|
|
23
|
-
"//input[@name='#{name}']"
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
Capybara.add_selector(:status) do
|
28
|
-
xpath do |name|
|
29
|
-
"//div[contains(@id, 'statusbar')]//div[text()='#{name}']"
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
Capybara.add_selector(:btn) do
|
34
|
-
xpath do |name|
|
35
|
-
".//span[text()='#{name}']"
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
Capybara.add_selector(:refresh) do
|
40
|
-
xpath do
|
41
|
-
".//div[contains(@class, 'x-tool-refresh')]"
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
Capybara.add_selector(:gridcolumn) do
|
46
|
-
xpath do |name|
|
47
|
-
".//span[contains(@class, 'x-column-header')][text()='#{name}']/.."
|
48
|
-
end
|
49
|
-
end
|
@@ -1,52 +0,0 @@
|
|
1
|
-
module Marty::RSpec::DownloadHelper
|
2
|
-
TIMEOUT = 10
|
3
|
-
PATH = Rails.root.join('spec/tmp/downloads')
|
4
|
-
|
5
|
-
ACCEPTED_EXTS = ['.xlsx', '.csv']
|
6
|
-
|
7
|
-
extend self
|
8
|
-
|
9
|
-
def downloads
|
10
|
-
Dir[PATH.join("*")]
|
11
|
-
end
|
12
|
-
|
13
|
-
def download
|
14
|
-
downloads.first
|
15
|
-
end
|
16
|
-
|
17
|
-
def download_content
|
18
|
-
wait_for_download
|
19
|
-
# doesn't work for excel files...
|
20
|
-
File.read(download)
|
21
|
-
end
|
22
|
-
|
23
|
-
def download_content_acceptable?
|
24
|
-
wait_for_download
|
25
|
-
downloads.each do |f|
|
26
|
-
return false unless ACCEPTED_EXTS.include? File.extname(f)
|
27
|
-
end
|
28
|
-
true
|
29
|
-
end
|
30
|
-
|
31
|
-
def wait_for_download
|
32
|
-
Timeout.timeout(TIMEOUT) do
|
33
|
-
sleep 0.1 until downloaded?
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def downloaded?
|
38
|
-
downloads.any? && !downloading?
|
39
|
-
end
|
40
|
-
|
41
|
-
def downloading?
|
42
|
-
downloads.grep(/\.part$/).any? ||
|
43
|
-
downloads.select { |f| File.size(f).zero? }.any?
|
44
|
-
end
|
45
|
-
|
46
|
-
def clear_downloads
|
47
|
-
FileUtils.rm_f(downloads)
|
48
|
-
Timeout.timeout(TIMEOUT) do
|
49
|
-
sleep 0.1 until !downloads.any?
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|