gooddata 0.6.10 → 0.6.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +9 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +6 -0
- data/README.md +1 -0
- data/gooddata.gemspec +38 -40
- data/lib/gooddata/bricks/base_downloader.rb +1 -1
- data/lib/gooddata/bricks/middleware/base_middleware.rb +36 -0
- data/lib/gooddata/bricks/middleware/bulk_salesforce_middleware.rb +8 -38
- data/lib/gooddata/bricks/middleware/decode_params_middleware.rb +14 -0
- data/lib/gooddata/bricks/middleware/fs_upload_middleware.rb +7 -6
- data/lib/gooddata/bricks/middleware/gooddata_middleware.rb +7 -5
- data/lib/gooddata/bricks/middleware/logger_middleware.rb +1 -1
- data/lib/gooddata/bricks/middleware/restforce_middleware.rb +20 -14
- data/lib/gooddata/bricks/middleware/undot_params_middleware.rb +33 -0
- data/lib/gooddata/cli/commands/api_cmd.rb +1 -1
- data/lib/gooddata/cli/commands/auth_cmd.rb +1 -1
- data/lib/gooddata/cli/commands/console_cmd.rb +2 -2
- data/lib/gooddata/cli/commands/process_cmd.rb +54 -7
- data/lib/gooddata/cli/commands/project_cmd.rb +9 -9
- data/lib/gooddata/cli/commands/projects_cmd.rb +1 -1
- data/lib/gooddata/cli/commands/run_ruby_cmd.rb +24 -7
- data/lib/gooddata/cli/commands/scaffold_cmd.rb +2 -2
- data/lib/gooddata/cli/commands/user_cmd.rb +1 -1
- data/lib/gooddata/cli/hooks.rb +3 -3
- data/lib/gooddata/commands/datasets.rb +1 -1
- data/lib/gooddata/commands/project.rb +2 -2
- data/lib/gooddata/commands/role.rb +1 -1
- data/lib/gooddata/commands/runners.rb +2 -2
- data/lib/gooddata/connection.rb +2 -2
- data/lib/gooddata/core/nil_logger.rb +1 -1
- data/lib/gooddata/core/rest.rb +12 -8
- data/lib/gooddata/data/guesser.rb +1 -1
- data/lib/gooddata/exceptions/attr_element_not_found.rb +1 -1
- data/lib/gooddata/extensions/enumerable.rb +1 -1
- data/lib/gooddata/extensions/hash.rb +20 -0
- data/lib/gooddata/helpers/csv_helper.rb +1 -1
- data/lib/gooddata/helpers/global_helpers.rb +59 -1
- data/lib/gooddata/mixins/md_lock.rb +83 -0
- data/lib/gooddata/mixins/md_object_indexer.rb +1 -1
- data/lib/gooddata/mixins/md_object_query.rb +1 -1
- data/lib/gooddata/mixins/md_relations.rb +0 -9
- data/lib/gooddata/models/dashboard_builder.rb +1 -1
- data/lib/gooddata/models/domain.rb +2 -2
- data/lib/gooddata/models/empty_result.rb +5 -5
- data/lib/gooddata/models/execution.rb +74 -0
- data/lib/gooddata/models/execution_detail.rb +74 -0
- data/lib/gooddata/models/membership.rb +1 -1
- data/lib/gooddata/models/metadata/attribute.rb +4 -6
- data/lib/gooddata/models/metadata/dashboard.rb +2 -0
- data/lib/gooddata/models/metadata/fact.rb +2 -2
- data/lib/gooddata/models/metadata/metric.rb +4 -1
- data/lib/gooddata/models/metadata/report.rb +84 -34
- data/lib/gooddata/models/metadata/report_definition.rb +28 -17
- data/lib/gooddata/models/metadata.rb +1 -1
- data/lib/gooddata/models/model.rb +1 -1
- data/lib/gooddata/models/process.rb +70 -54
- data/lib/gooddata/models/profile.rb +47 -10
- data/lib/gooddata/models/project.rb +74 -30
- data/lib/gooddata/models/project_blueprint.rb +9 -10
- data/lib/gooddata/models/project_builder.rb +2 -2
- data/lib/gooddata/models/project_creator.rb +4 -4
- data/lib/gooddata/models/report_data_result.rb +1 -1
- data/lib/gooddata/models/schedule.rb +39 -32
- data/lib/gooddata/models/to_manifest.rb +5 -5
- data/lib/gooddata/models/to_wire.rb +3 -3
- data/lib/gooddata/rest/client.rb +64 -31
- data/lib/gooddata/rest/connection.rb +7 -7
- data/lib/gooddata/rest/connections/dummy_connection.rb +5 -5
- data/lib/gooddata/rest/connections/rest_client_connection.rb +106 -44
- data/lib/gooddata/rest/object.rb +1 -1
- data/lib/gooddata/version.rb +1 -1
- data/spec/bricks/bricks_spec.rb +67 -0
- data/spec/bricks/default-config.json +8 -0
- data/spec/data/gooddata_version_process/gooddata_version.rb +3 -0
- data/spec/data/gooddata_version_process/gooddata_version.zip +0 -0
- data/spec/data/ruby_params_process/ruby_params.rb +3 -0
- data/spec/helpers/process_helper.rb +12 -0
- data/spec/helpers/schedule_helper.rb +21 -0
- data/spec/integration/create_project_spec.rb +19 -0
- data/spec/integration/full_process_schedule_spec.rb +129 -8
- data/spec/integration/full_project_spec.rb +52 -2
- data/spec/spec_helper.rb +1 -0
- data/spec/unit/core/rest_spec.rb +76 -3
- data/spec/unit/helpers_spec.rb +43 -0
- data/spec/unit/models/metric_spec.rb +33 -0
- data/spec/unit/models/params_spec.rb +96 -0
- data/spec/unit/models/profile_spec.rb +16 -0
- data/spec/unit/models/schedule_spec.rb +12 -3
- metadata +350 -187
- data/lib/gooddata/helper/class_helper.rb +0 -1
- data/lib/gooddata/helper/helpers.rb +0 -8
data/lib/gooddata/rest/object.rb
CHANGED
data/lib/gooddata/version.rb
CHANGED
data/spec/bricks/bricks_spec.rb
CHANGED
@@ -17,6 +17,73 @@ describe GoodData::Bricks do
|
|
17
17
|
p.call({})
|
18
18
|
end
|
19
19
|
|
20
|
+
describe "#load_defaults" do
|
21
|
+
context "when you define a middleware with default_loaded_call and give it some defaults file with prefix" do
|
22
|
+
class TestMiddleWare < GoodData::Bricks::Middleware
|
23
|
+
def initialize(options={})
|
24
|
+
@config = 'spec/bricks/default-config.json'
|
25
|
+
super(options)
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(params)
|
29
|
+
params = super(params)
|
30
|
+
my_stuff = params['config']['my']['namespace']
|
31
|
+
puts "Now I have the defaults and runtime parameters merged and loaded: #{my_stuff['key']}"
|
32
|
+
|
33
|
+
# Doing something cool and puting it into params
|
34
|
+
params['something_cool'] = "#{my_stuff['key']} and also #{my_stuff['default_key']}"
|
35
|
+
|
36
|
+
@app.call(params)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class TestBrick
|
41
|
+
def call(params)
|
42
|
+
# doing something with params
|
43
|
+
puts "Brick: #{params['something_cool']}"
|
44
|
+
params
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it "puts them into params" do
|
49
|
+
p = GoodData::Bricks::Pipeline.prepare([
|
50
|
+
TestMiddleWare,
|
51
|
+
TestBrick
|
52
|
+
])
|
53
|
+
|
54
|
+
res = p.call({
|
55
|
+
'config' => {
|
56
|
+
'my' => {
|
57
|
+
'namespace' => {
|
58
|
+
'key' => 'redefined value',
|
59
|
+
'new_key' => 'new value'
|
60
|
+
}
|
61
|
+
},
|
62
|
+
'other_namespace' => {
|
63
|
+
'some_key' => 'some value'
|
64
|
+
}
|
65
|
+
}
|
66
|
+
})
|
67
|
+
|
68
|
+
res.should eq({
|
69
|
+
'config' => {
|
70
|
+
'my' => {
|
71
|
+
'namespace' => {
|
72
|
+
'key' => 'redefined value',
|
73
|
+
'new_key' => 'new value',
|
74
|
+
'default_key' => 'default value 2'
|
75
|
+
}
|
76
|
+
},
|
77
|
+
'other_namespace' => {
|
78
|
+
'some_key' => 'some value'
|
79
|
+
}
|
80
|
+
},
|
81
|
+
"something_cool" => "redefined value and also default value 2"
|
82
|
+
})
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
20
87
|
|
21
88
|
# TODO: Better test pre and post so we are sure it is executed in right order
|
22
89
|
it "should be possible to use instance both as middleware and app" do
|
Binary file
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
# Global requires
|
4
4
|
require 'multi_json'
|
5
|
+
require 'pmap'
|
5
6
|
|
6
7
|
# Local requires
|
7
8
|
require 'gooddata/models/models'
|
@@ -9,4 +10,15 @@ require 'gooddata/models/models'
|
|
9
10
|
module ProcessHelper
|
10
11
|
PROCESS_ID = 'dc143d80-58a1-4acd-96b6-8d11fc4571de'
|
11
12
|
DEPLOY_NAME = 'graph'
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def remove_old_processes(project)
|
16
|
+
processes = project.processes
|
17
|
+
processes.pmap do |process|
|
18
|
+
next if process.obj_id == PROCESS_ID
|
19
|
+
puts "Deleting #{process.inspect}"
|
20
|
+
process.delete
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
12
24
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'pmap'
|
4
|
+
|
5
|
+
require_relative 'process_helper'
|
6
|
+
|
7
|
+
module ScheduleHelper
|
8
|
+
SCHEDULE_ID = '53e029bde4b035034ad4abb6'
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def remove_old_schedules(project)
|
12
|
+
schedules = project.schedules
|
13
|
+
schedules.pmap do |schedule|
|
14
|
+
next if schedule.obj_id == SCHEDULE_ID
|
15
|
+
|
16
|
+
puts "Deleting #{schedule.inspect}"
|
17
|
+
schedule.delete
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'gooddata'
|
2
|
+
|
3
|
+
describe 'Create project using GoodData client', :constraint => 'slow' do
|
4
|
+
before(:all) do
|
5
|
+
@client = ConnectionHelper.create_default_connection
|
6
|
+
end
|
7
|
+
|
8
|
+
after(:all) do
|
9
|
+
@client.disconnect
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'Should create project using GoodData::Rest::Client#create_project' do
|
13
|
+
project_title = 'Test #create_project'
|
14
|
+
project = @client.create_project(:title => project_title, :auth_token => ConnectionHelper::GD_PROJECT_TOKEN)
|
15
|
+
expect(project.title).to eq(project_title)
|
16
|
+
project.delete
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -1,6 +1,25 @@
|
|
1
1
|
require 'gooddata'
|
2
2
|
|
3
3
|
describe "Full process and schedule exercise", :constraint => 'slow' do
|
4
|
+
COMPLEX_PARAMS ||= {
|
5
|
+
type: 'Person',
|
6
|
+
model_version: 1,
|
7
|
+
data_version: 1.5,
|
8
|
+
some_true_flag: true,
|
9
|
+
some_false_flag: false,
|
10
|
+
empty_value: nil,
|
11
|
+
user: {
|
12
|
+
firstname: 'Joe',
|
13
|
+
lastname: 'Doe',
|
14
|
+
age: 42
|
15
|
+
},
|
16
|
+
address: {
|
17
|
+
street: '#111 Sutter St.',
|
18
|
+
city: 'San Francisco',
|
19
|
+
zip: '94133'
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
4
23
|
before(:all) do
|
5
24
|
@client = ConnectionHelper::create_default_connection
|
6
25
|
@project = @client.create_project(title: 'Project for schedule testing', auth_token: ConnectionHelper::GD_PROJECT_TOKEN)
|
@@ -17,23 +36,50 @@ describe "Full process and schedule exercise", :constraint => 'slow' do
|
|
17
36
|
|
18
37
|
it "should be able to execute a process" do
|
19
38
|
result = @process.execute(@process.executables.first)
|
20
|
-
log =
|
39
|
+
log = result.log
|
21
40
|
expect(log.index('Hello Ruby executors')).not_to eq nil
|
22
41
|
expect(log.index('Hello Ruby from the deep')).not_to eq nil
|
23
42
|
end
|
24
43
|
|
25
|
-
it "should be able to
|
44
|
+
it "should be able to start executing a process" do
|
45
|
+
result = @process.start_execution(@process.executables.first)
|
46
|
+
expect(result["executionTask"]).not_to be_nil
|
47
|
+
expect(result["executionTask"]['links']['detail']).not_to be_nil
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should be able to grab executables" do
|
26
51
|
|
27
|
-
expect(@process.executables).to eq ['
|
52
|
+
expect(@process.executables).to eq ['process.rb']
|
28
53
|
end
|
29
54
|
|
30
|
-
it "should have empty schedules on deploy" do
|
55
|
+
it "should have empty schedules on deploy" do
|
31
56
|
expect(@process.schedules).to eq []
|
32
57
|
end
|
33
58
|
|
59
|
+
it "should be able to create schedule triggered by another schedule" do
|
60
|
+
schedule_first = @process.create_schedule('0 15 27 7 *', @process.executables.first)
|
61
|
+
schedule = @process.create_schedule(schedule_first, @process.executables.first)
|
62
|
+
res = @process.schedules
|
63
|
+
expect(res.count).to eq 2
|
64
|
+
expect(@process.schedules.map(&:uri)).to include(schedule_first.uri, schedule.uri)
|
65
|
+
schedule.delete
|
66
|
+
schedule_first.delete
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should be able to create schedule triggered by another schedule specified by ID" do
|
70
|
+
schedule_first = @process.create_schedule('0 15 27 7 *', @process.executables.first)
|
71
|
+
schedule = @process.create_schedule(schedule_first.obj_id, @process.executables.first)
|
72
|
+
res = @process.schedules
|
73
|
+
expect(res.count).to eq 2
|
74
|
+
expect(@process.schedules.map(&:uri)).to include(schedule_first.uri, schedule.uri)
|
75
|
+
schedule.delete
|
76
|
+
schedule_first.delete
|
77
|
+
end
|
78
|
+
|
34
79
|
it "should be able to delete schedule" do
|
35
80
|
schedule = @process.create_schedule('0 15 27 7 *', @process.executables.first)
|
36
|
-
|
81
|
+
res = @process.schedules
|
82
|
+
expect(res.count).to eq 1
|
37
83
|
expect(@process.schedules).to eq [schedule]
|
38
84
|
schedule.delete
|
39
85
|
end
|
@@ -47,7 +93,8 @@ describe "Full process and schedule exercise", :constraint => 'slow' do
|
|
47
93
|
it "should be possible to execute schedule" do
|
48
94
|
schedule = @process.create_schedule('0 15 27 7 *', @process.executables.first)
|
49
95
|
result = schedule.execute
|
50
|
-
|
96
|
+
expect(result.status).to eq :ok
|
97
|
+
log = result.log
|
51
98
|
expect(log.index('Hello Ruby executors')).not_to eq nil
|
52
99
|
expect(log.index('Hello Ruby from the deep')).not_to eq nil
|
53
100
|
end
|
@@ -59,7 +106,8 @@ describe "Full process and schedule exercise", :constraint => 'slow' do
|
|
59
106
|
begin
|
60
107
|
schedule = process.create_schedule('0 15 27 7 *', process.executables.first)
|
61
108
|
result = schedule.execute
|
62
|
-
|
109
|
+
expect(result.status).to eq :ok
|
110
|
+
log = result.log
|
63
111
|
expect(log.index('HELLO WORLD')).not_to eq nil
|
64
112
|
expect(schedule.enabled?).to be_true
|
65
113
|
schedule.disable
|
@@ -70,6 +118,7 @@ describe "Full process and schedule exercise", :constraint => 'slow' do
|
|
70
118
|
schedule.save
|
71
119
|
expect(schedule.enabled?).to be_true
|
72
120
|
ensure
|
121
|
+
schedule && schedule.delete
|
73
122
|
process && process.delete
|
74
123
|
end
|
75
124
|
end
|
@@ -82,9 +131,81 @@ describe "Full process and schedule exercise", :constraint => 'slow' do
|
|
82
131
|
expect(process.schedules.count).to eq 0
|
83
132
|
schedule = process.create_schedule('0 15 27 7 *', process.executables.first)
|
84
133
|
result = schedule.execute
|
85
|
-
|
134
|
+
expect(result.status).to eq :ok
|
135
|
+
log = result.log
|
86
136
|
expect(log.index('HELLO WORLD')).not_to eq nil
|
87
137
|
expect(process.schedules.count).to eq 1
|
138
|
+
ensure
|
139
|
+
schedule && schedule.delete
|
140
|
+
process && process.delete
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'should be possible to deploy and run zipped file and print GoodData::VERSION' do
|
145
|
+
process = @project.deploy_process('./spec/data/gooddata_version_process/gooddata_version.zip',
|
146
|
+
type: 'RUBY',
|
147
|
+
name: 'Test ETL zipped file GoodData Process')
|
148
|
+
begin
|
149
|
+
expect(process.schedules.count).to eq 0
|
150
|
+
schedule = process.create_schedule('0 15 27 7 *', process.executables.first)
|
151
|
+
result = schedule.execute
|
152
|
+
expect(result.status).to eq :ok
|
153
|
+
log = result.log
|
154
|
+
expect(log.index(GoodData::VERSION)).not_to eq nil
|
155
|
+
expect(process.schedules.count).to eq 1
|
156
|
+
ensure
|
157
|
+
schedule && schedule.delete
|
158
|
+
process && process.delete
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'should be possible to deploy and run directory and use nested parameters' do
|
163
|
+
process = @project.deploy_process('./spec/data/ruby_params_process',
|
164
|
+
type: 'RUBY',
|
165
|
+
name: 'Test ETL dir GoodData Process')
|
166
|
+
begin
|
167
|
+
expect(process.schedules.count).to eq 0
|
168
|
+
schedule = process.create_schedule('0 15 27 7 *', process.executables.first, params: COMPLEX_PARAMS)
|
169
|
+
result = schedule.execute
|
170
|
+
expect(result.status).to eq :ok
|
171
|
+
log = result.log
|
172
|
+
expect(log.index('Joe')).not_to eq nil
|
173
|
+
expect(log.index('San Francisco')).not_to eq nil
|
174
|
+
expect(process.schedules.count).to eq 1
|
175
|
+
ensure
|
176
|
+
schedule && schedule.delete
|
177
|
+
process && process.delete
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'should be possible to deploy and run directory and use nested hidden parameters' do
|
182
|
+
process = @project.deploy_process('./spec/data/ruby_params_process',
|
183
|
+
type: 'RUBY',
|
184
|
+
name: 'Test ETL dir GoodData Process')
|
185
|
+
begin
|
186
|
+
expect(process.schedules.count).to eq 0
|
187
|
+
schedule = process.create_schedule('0 15 27 7 *', process.executables.first, hidden_params: COMPLEX_PARAMS)
|
188
|
+
result = schedule.execute
|
189
|
+
# expect(result.status).to eq :ok
|
190
|
+
log = result.log
|
191
|
+
expect(process.schedules.count).to eq 1
|
192
|
+
ensure
|
193
|
+
schedule && schedule.delete
|
194
|
+
process && process.delete
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should be possible to download deployed process" do
|
199
|
+
size = File.size('./spec/data/hello_world_process/hello_world.zip')
|
200
|
+
process = @project.deploy_process('./spec/data/hello_world_process/hello_world.zip',
|
201
|
+
type: 'RUBY',
|
202
|
+
name: 'Test ETL zipped file Process')
|
203
|
+
begin
|
204
|
+
Tempfile.open('downloaded-process') do |temp|
|
205
|
+
temp << process.download
|
206
|
+
temp.flush
|
207
|
+
expect(File.size(temp.path)).to eq size
|
208
|
+
end
|
88
209
|
ensure
|
89
210
|
process && process.delete
|
90
211
|
end
|
@@ -109,6 +109,26 @@ describe "Full project implementation", :constraint => 'slow' do
|
|
109
109
|
expect(result2).to eq result
|
110
110
|
end
|
111
111
|
|
112
|
+
it "should be able to lock reports and everything underneath" do
|
113
|
+
m = @project.metrics.first
|
114
|
+
r = @project.create_report(top: [m], title: 'xy')
|
115
|
+
r.save
|
116
|
+
expect(m.locked?).to eq false
|
117
|
+
expect(r.locked?).to eq false
|
118
|
+
r.lock_with_dependencies!
|
119
|
+
expect(r.locked?).to eq true
|
120
|
+
m.reload!
|
121
|
+
expect(m.locked?).to eq true
|
122
|
+
r.unlock_with_dependencies!
|
123
|
+
expect(r.locked?).to eq false
|
124
|
+
m.reload!
|
125
|
+
expect(m.locked?).to eq false
|
126
|
+
r.lock!
|
127
|
+
expect(r.locked?).to eq true
|
128
|
+
r.unlock!
|
129
|
+
expect(r.locked?).to eq false
|
130
|
+
end
|
131
|
+
|
112
132
|
it "should be able to purge report from older revisions" do
|
113
133
|
m = @project.metrics.first
|
114
134
|
r = @project.create_report(top: [m], title: 'xy')
|
@@ -121,6 +141,25 @@ describe "Full project implementation", :constraint => 'slow' do
|
|
121
141
|
expect(r.definitions.count).to eq 2
|
122
142
|
end
|
123
143
|
|
144
|
+
it "should be able to clean colors from a chart report def" do
|
145
|
+
f = @project.fact_by_title('Lines Changed')
|
146
|
+
m = @project.create_metric("SELECT SUM(#\"#{f.title}\")", title: 'test metric').save
|
147
|
+
r = @project.create_report(top: [m], title: 'xy')
|
148
|
+
rd = r.latest_report_definition
|
149
|
+
rd.content['chart'] = { 'styles' => { 'global' => { 'colorMapping' => 1 } } }
|
150
|
+
expect(GoodData::Helpers.get_path(rd.content, %w(chart styles global))).to eq ({ 'colorMapping' => 1 })
|
151
|
+
rd.reset_color_mapping!
|
152
|
+
expect(GoodData::Helpers.get_path(rd.content, %w(chart styles global))).to eq ({ 'colorMapping' => [] })
|
153
|
+
r.delete
|
154
|
+
res = m.used_by
|
155
|
+
res.each do |dependency|
|
156
|
+
@client.delete dependency['link']
|
157
|
+
end
|
158
|
+
res = m.used_by
|
159
|
+
expect(res.length).to eq 0
|
160
|
+
m.delete
|
161
|
+
end
|
162
|
+
|
124
163
|
it "should be possible to get all metrics" do
|
125
164
|
metrics1 = @project.metrics
|
126
165
|
expect(metrics1.count).to be >= 0
|
@@ -176,10 +215,12 @@ describe "Full project implementation", :constraint => 'slow' do
|
|
176
215
|
expect(fact1).not_to eq fact3
|
177
216
|
|
178
217
|
metric.using(nil)
|
179
|
-
|
218
|
+
res = metric.using('fact')
|
219
|
+
expect(res.count).to eq 1
|
180
220
|
|
181
221
|
fact1.used_by(nil)
|
182
|
-
|
222
|
+
res = fact1.used_by('metric')
|
223
|
+
expect(res.count).to eq 1
|
183
224
|
|
184
225
|
res = metric.using?(fact1)
|
185
226
|
expect(res).to be(true)
|
@@ -362,4 +403,13 @@ describe "Full project implementation", :constraint => 'slow' do
|
|
362
403
|
expect(cloned_project.facts.first.create_metric.execute).to eq nil
|
363
404
|
cloned_project.delete
|
364
405
|
end
|
406
|
+
|
407
|
+
it "should be able to delete report along with its definitions" do
|
408
|
+
m = @project.metrics.first
|
409
|
+
r = @project.create_report(top: [m], title: 'Report to delete')
|
410
|
+
r.save
|
411
|
+
def_uris = r.definition_uris
|
412
|
+
r.delete
|
413
|
+
expect { def_uris.each {|uri| @client.get(uri)} }.to raise_error(RestClient::ResourceNotFound)
|
414
|
+
end
|
365
415
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/unit/core/rest_spec.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
+
require 'tempfile'
|
2
3
|
|
3
4
|
require 'gooddata/core/rest'
|
4
5
|
|
@@ -18,13 +19,85 @@ describe GoodData do
|
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
22
|
+
|
23
|
+
def test_webdav_upload(params)
|
24
|
+
GoodData.with_project(@project, :client => @client) do
|
25
|
+
dir = Time.now.to_i.to_s
|
26
|
+
|
27
|
+
path = 'spec/data/test-ci-data.csv'
|
28
|
+
|
29
|
+
if params[:special_chars]
|
30
|
+
source_file = Tempfile.new('abc-16:55:29+ha#he.csv')
|
31
|
+
FileUtils.cp(path, source_file)
|
32
|
+
path = source_file.path
|
33
|
+
end
|
34
|
+
|
35
|
+
path = File.expand_path(path) if params[:absolute_path]
|
36
|
+
|
37
|
+
# upload it there
|
38
|
+
upload_method = GoodData.method(params[:upload_method])
|
39
|
+
upload_method.call(path, directory: dir)
|
40
|
+
|
41
|
+
# download it from there
|
42
|
+
file = Tempfile.new('foo.csv')
|
43
|
+
|
44
|
+
download_method = GoodData.method(params[:download_method])
|
45
|
+
download_method.call(File.basename(path), file, directory: dir)
|
46
|
+
|
47
|
+
expect(file.size).to be > 0
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
21
51
|
describe '#upload_to_project_webdav' do
|
22
|
-
it 'Uploads file' do
|
23
|
-
|
24
|
-
|
52
|
+
it 'Uploads file with relative path to a dir' do
|
53
|
+
test_webdav_upload(
|
54
|
+
upload_method: 'upload_to_project_webdav',
|
55
|
+
download_method: 'download_from_project_webdav'
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'Uploads file with absolute path to a dir' do
|
60
|
+
test_webdav_upload(
|
61
|
+
absolute_path: true,
|
62
|
+
upload_method: 'upload_to_project_webdav',
|
63
|
+
download_method: 'download_from_project_webdav'
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'Uploads file with special chars in filename' do
|
68
|
+
test_webdav_upload(
|
69
|
+
special_chars: true,
|
70
|
+
upload_method: 'upload_to_project_webdav',
|
71
|
+
download_method: 'download_from_project_webdav'
|
72
|
+
)
|
25
73
|
end
|
26
74
|
end
|
27
75
|
|
76
|
+
describe '#upload_to_user_webdav' do
|
77
|
+
it 'Uploads file with relative path to a dir' do
|
78
|
+
test_webdav_upload(
|
79
|
+
upload_method: 'upload_to_user_webdav',
|
80
|
+
download_method: 'download_from_user_webdav'
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'Uploads file with absolute path to a dir' do
|
85
|
+
test_webdav_upload(
|
86
|
+
absolute_path: true,
|
87
|
+
upload_method: 'upload_to_user_webdav',
|
88
|
+
download_method: 'download_from_user_webdav'
|
89
|
+
)
|
90
|
+
end
|
91
|
+
it 'Uploads file with special chars in filename' do
|
92
|
+
test_webdav_upload(
|
93
|
+
special_chars: true,
|
94
|
+
upload_method: 'upload_to_user_webdav',
|
95
|
+
download_method: 'download_from_user_webdav'
|
96
|
+
)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
28
101
|
describe '#get_user_webdav_path' do
|
29
102
|
it 'Gets the path' do
|
30
103
|
@client.get_user_webdav_path('test.csv', :project => @project)
|
data/spec/unit/helpers_spec.rb
CHANGED
@@ -44,4 +44,47 @@ describe GoodData::Helpers do
|
|
44
44
|
result.should == expect
|
45
45
|
end
|
46
46
|
end
|
47
|
+
|
48
|
+
describe "#decode_params" do
|
49
|
+
it 'decodes the data params from json' do
|
50
|
+
params = {
|
51
|
+
'param' => 'value',
|
52
|
+
'number_param' => 5,
|
53
|
+
'gd_encoded_params' => '{"deep": {"deeper": "deep value"}}',
|
54
|
+
}
|
55
|
+
expected_result = {
|
56
|
+
'param' => 'value',
|
57
|
+
'number_param' => 5,
|
58
|
+
'deep' => {
|
59
|
+
'deeper' => 'deep value'
|
60
|
+
}
|
61
|
+
}
|
62
|
+
result = GoodData::Helpers.decode_params(params)
|
63
|
+
expect(result).to eq(expected_result)
|
64
|
+
end
|
65
|
+
it 'decodes the hidden_data in hidden params' do
|
66
|
+
params = {
|
67
|
+
'param' => 'value',
|
68
|
+
'number_param' => 5,
|
69
|
+
'gd_encoded_hidden_params' => '{"deep_secret": {"deeper_secret": "hidden value"}}'
|
70
|
+
}
|
71
|
+
expected_result = {
|
72
|
+
'param' => 'value',
|
73
|
+
'number_param' => 5,
|
74
|
+
"deep_secret" => {
|
75
|
+
"deeper_secret" => "hidden value"
|
76
|
+
}
|
77
|
+
}
|
78
|
+
result = GoodData::Helpers.decode_params(params)
|
79
|
+
expect(result).to eq(expected_result)
|
80
|
+
end
|
81
|
+
it 'throws an error when data params is not a valid json' do
|
82
|
+
params = {
|
83
|
+
'param' => 'value',
|
84
|
+
'number_param' => 5,
|
85
|
+
'gd_encoded_params' => 'This is no json.'
|
86
|
+
}
|
87
|
+
expect { GoodData::Helpers.decode_params(params) }.to raise_error(JSON::ParserError)
|
88
|
+
end
|
89
|
+
end
|
47
90
|
end
|
@@ -17,6 +17,7 @@ describe GoodData::Metric do
|
|
17
17
|
'identifier' => 'afo7bx1VakCz',
|
18
18
|
'deprecated' => '0',
|
19
19
|
'summary' => '',
|
20
|
+
'locked' => 0,
|
20
21
|
'title' => 'sum of Lines changed',
|
21
22
|
'category' => 'metric',
|
22
23
|
'updated' => '2014-05-05 20:00:42',
|
@@ -34,6 +35,7 @@ describe GoodData::Metric do
|
|
34
35
|
'identifier' => 'afo7bx1VakCz',
|
35
36
|
'deprecated' => '0',
|
36
37
|
'summary' => '',
|
38
|
+
'locked' => 1,
|
37
39
|
'title' => 'sum of Lines changed',
|
38
40
|
'category' => 'metric',
|
39
41
|
'updated' => '2014-05-05 20:00:42',
|
@@ -55,6 +57,7 @@ describe GoodData::Metric do
|
|
55
57
|
'identifier' => 'afo7bx1VakCz',
|
56
58
|
'deprecated' => '0',
|
57
59
|
'summary' => '',
|
60
|
+
'locked' => 0,
|
58
61
|
'title' => 'sum of Lines changed',
|
59
62
|
'category' => 'metric',
|
60
63
|
'updated' => '2014-05-05 20:00:42',
|
@@ -89,4 +92,34 @@ describe GoodData::Metric do
|
|
89
92
|
@instance.contain?(UNUSED_METRIC).should == true
|
90
93
|
end
|
91
94
|
end
|
95
|
+
|
96
|
+
describe "#locked?" do
|
97
|
+
it "should be able to say if an object is locked" do
|
98
|
+
expect(@instance.locked?).to eq false
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "#unlocked?" do
|
103
|
+
it "should be able to say if an object is unlocked" do
|
104
|
+
expect(@instance.unlocked?).to eq true
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "#lock" do
|
109
|
+
it "should be able to lock an object" do
|
110
|
+
expect(@instance.locked?).to eq false
|
111
|
+
@instance.lock
|
112
|
+
expect(@instance.locked?).to eq true
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "#lock" do
|
117
|
+
it "should be able to unlock an object" do
|
118
|
+
@instance.lock
|
119
|
+
expect(@instance.locked?).to eq true
|
120
|
+
@instance.unlock
|
121
|
+
expect(@instance.locked?).to eq false
|
122
|
+
expect(@instance.unlocked?).to eq true
|
123
|
+
end
|
124
|
+
end
|
92
125
|
end
|