gooddata 0.6.3 → 0.6.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -1
  3. data/CHANGELOG.markdown +6 -0
  4. data/README.md +1 -0
  5. data/gooddata.gemspec +2 -1
  6. data/lib/gooddata.rb +4 -1
  7. data/lib/gooddata/bricks/base_downloader.rb +33 -19
  8. data/lib/gooddata/bricks/middleware/bulk_salesforce_middleware.rb +49 -25
  9. data/lib/gooddata/bricks/middleware/restforce_middleware.rb +36 -33
  10. data/lib/gooddata/cli/commands/project_cmd.rb +6 -4
  11. data/lib/gooddata/client.rb +1 -1
  12. data/lib/gooddata/commands/api.rb +1 -1
  13. data/lib/gooddata/commands/auth.rb +1 -1
  14. data/lib/gooddata/connection.rb +13 -10
  15. data/lib/gooddata/core/connection.rb +1 -1
  16. data/lib/gooddata/core/user.rb +11 -3
  17. data/lib/gooddata/exceptions/validation_error.rb +12 -0
  18. data/lib/gooddata/extensions/extensions.rb +6 -0
  19. data/lib/gooddata/goodzilla/goodzilla.rb +2 -2
  20. data/lib/gooddata/helpers/csv_helper.rb +57 -0
  21. data/lib/gooddata/{helpers.rb → helpers/global_helpers.rb} +0 -0
  22. data/lib/gooddata/helpers/helpers.rb +6 -0
  23. data/lib/gooddata/models/domain.rb +134 -24
  24. data/lib/gooddata/models/membership.rb +402 -0
  25. data/lib/gooddata/models/metadata.rb +64 -7
  26. data/lib/gooddata/models/metadata/attribute.rb +27 -12
  27. data/lib/gooddata/models/metadata/column.rb +1 -1
  28. data/lib/gooddata/models/metadata/dashboard.rb +7 -6
  29. data/lib/gooddata/models/metadata/display_form.rb +17 -2
  30. data/lib/gooddata/models/metadata/fact.rb +13 -7
  31. data/lib/gooddata/models/metadata/metric.rb +9 -9
  32. data/lib/gooddata/models/metadata/report.rb +7 -8
  33. data/lib/gooddata/models/metadata/report_definition.rb +10 -11
  34. data/lib/gooddata/models/metadata/schema.rb +1 -1
  35. data/lib/gooddata/models/model.rb +1 -1
  36. data/lib/gooddata/models/process.rb +44 -25
  37. data/lib/gooddata/models/profile.rb +365 -13
  38. data/lib/gooddata/models/project.rb +245 -35
  39. data/lib/gooddata/models/project_blueprint.rb +42 -18
  40. data/lib/gooddata/models/project_creator.rb +4 -1
  41. data/lib/gooddata/models/project_role.rb +7 -7
  42. data/lib/gooddata/models/schedule.rb +17 -1
  43. data/lib/gooddata/models/schema_blueprint.rb +19 -2
  44. data/lib/gooddata/version.rb +1 -1
  45. data/out.txt +0 -0
  46. data/spec/data/users.csv +12 -0
  47. data/spec/helpers/connection_helper.rb +1 -0
  48. data/spec/helpers/csv_helper.rb +12 -0
  49. data/spec/helpers/project_helper.rb +1 -1
  50. data/spec/integration/full_project_spec.rb +136 -3
  51. data/spec/spec_helper.rb +9 -0
  52. data/spec/unit/commands/command_user_spec.rb +1 -1
  53. data/spec/unit/extensions/hash_spec.rb +19 -0
  54. data/spec/unit/godzilla/goodzilla_spec.rb +15 -0
  55. data/spec/unit/helpers/csv_helper_spec.rb +18 -0
  56. data/spec/unit/models/domain_spec.rb +47 -4
  57. data/spec/unit/models/md_object_spec.rb +8 -0
  58. data/spec/unit/models/membership_spec.rb +128 -0
  59. data/spec/unit/models/metadata_spec.rb +38 -0
  60. data/spec/unit/models/profile_spec.rb +212 -0
  61. data/spec/unit/models/project_blueprint_spec.rb +35 -8
  62. data/spec/unit/models/project_role_spec.rb +6 -6
  63. data/spec/unit/models/project_spec.rb +226 -13
  64. data/spec/unit/models/schedule_spec.rb +58 -0
  65. data/tmp/.gitkeepme +0 -0
  66. metadata +36 -11
  67. data/lib/gooddata/models/account_settings.rb +0 -124
  68. data/lib/gooddata/models/user.rb +0 -165
  69. data/spec/unit/models/account_settings_spec.rb +0 -28
  70. data/spec/unit/models/user_spec.rb +0 -16
@@ -1,5 +1,4 @@
1
1
  # encoding: UTF-8
2
-
3
2
  require 'gooddata'
4
3
 
5
4
  describe GoodData::Model::ProjectBlueprint do
@@ -20,19 +19,34 @@ describe GoodData::Model::ProjectBlueprint do
20
19
  end
21
20
 
22
21
  it 'valid blueprint should be marked as valid' do
23
- @blueprint.model_valid?.should == true
22
+ @blueprint.valid?.should == true
24
23
  end
25
24
 
26
25
  it 'valid blueprint should give you empty array of errors' do
27
- expect(@blueprint.validate_model).to be_empty
26
+ expect(@blueprint.validate).to be_empty
27
+ end
28
+
29
+ it 'model should be invalid if it contains more than one anchor' do
30
+ builder = GoodData::Model::ProjectBuilder.create("my_bp") do |p|
31
+ p.add_dataset("repos") do |d|
32
+ d.add_anchor("repo_id")
33
+ d.add_anchor("repo_id2")
34
+ d.add_attribute("name")
35
+ end
36
+ end
37
+ bp = GoodData::Model::ProjectBlueprint.new(builder)
38
+ bp.valid?.should == false
39
+ errors = bp.validate
40
+ errors.first.should == {:anchor => 2}
41
+ errors.count.should == 1
28
42
  end
29
43
 
30
44
  it 'invalid blueprint should be marked as invalid' do
31
- @invalid_blueprint.model_valid?.should == false
45
+ @invalid_blueprint.valid?.should == false
32
46
  end
33
47
 
34
48
  it 'invalid blueprint should give you list of violating references' do
35
- errors = @invalid_blueprint.validate_model
49
+ errors = @invalid_blueprint.validate
36
50
  errors.size.should == 1
37
51
  errors.first.should == {
38
52
  type: 'reference',
@@ -47,6 +61,19 @@ describe GoodData::Model::ProjectBlueprint do
47
61
  expect(refs).to be_empty
48
62
  end
49
63
 
64
+ it "should be possible to create from ProjectBlueprint from ProjectBuilder in several ways" do
65
+ builder = GoodData::Model::SchemaBuilder.new("stuff") do |d|
66
+ d.add_attribute("id", :title => "My Id")
67
+ d.add_fact("amount", :title => "Amount")
68
+ end
69
+
70
+ bp1 = GoodData::Model::ProjectBlueprint.new(builder)
71
+ bp1.valid?.should == true
72
+
73
+ bp2 = builder.to_blueprint
74
+ bp2.valid?.should == true
75
+ end
76
+
50
77
  it 'should be able to get dataset by name' do
51
78
  ds = @blueprint.find_dataset('devs')
52
79
  ds.name.should == 'devs'
@@ -107,9 +134,9 @@ describe GoodData::Model::ProjectBlueprint do
107
134
  d.add_label("name", :reference => "invalid_ref")
108
135
  end
109
136
  end
110
- bp = GoodData::Model::ProjectBlueprint.from_json(builder.to_hash)
111
- bp.model_valid?.should == false
112
- errors = bp.validate_model
137
+ bp = GoodData::Model::ProjectBlueprint.new(builder)
138
+ bp.valid?.should == false
139
+ errors = bp.validate
113
140
  errors.count.should == 1
114
141
  end
115
142
 
@@ -16,16 +16,16 @@ describe GoodData::ProjectRole do
16
16
  end
17
17
 
18
18
  describe '#author' do
19
- it 'Returns author as GoodData::AccountSettings' do
19
+ it 'Returns author as GoodData::Profile' do
20
20
  res = @role.author
21
- expect(res).to be_an_instance_of(GoodData::AccountSettings)
21
+ expect(res).to be_an_instance_of(GoodData::Profile)
22
22
  end
23
23
  end
24
24
 
25
25
  describe '#contributor' do
26
- it 'Returns contributor as GoodData::AccountSettings' do
26
+ it 'Returns contributor as GoodData::Profile' do
27
27
  res = @role.contributor
28
- expect(res).to be_an_instance_of(GoodData::AccountSettings)
28
+ expect(res).to be_an_instance_of(GoodData::Profile)
29
29
  end
30
30
  end
31
31
 
@@ -79,11 +79,11 @@ describe GoodData::ProjectRole do
79
79
  end
80
80
 
81
81
  describe '#users' do
82
- it 'Returns users as Array<GoodData::AccountSettings>' do
82
+ it 'Returns users as Array<GoodData::Profile>' do
83
83
  res = @role.users
84
84
  expect(res).to be_an_instance_of(Array)
85
85
  res.each do |user|
86
- expect(user).to be_an_instance_of(GoodData::AccountSettings)
86
+ expect(user).to be_an_instance_of(GoodData::Profile)
87
87
  end
88
88
  end
89
89
  end
@@ -11,13 +11,38 @@ describe GoodData::Project do
11
11
  GoodData.disconnect
12
12
  end
13
13
 
14
+ def load_users_from_csv
15
+ GoodData::Helpers::Csv.read(:path => CsvHelper::CSV_PATH_IMPORT, :header => true) do |row|
16
+ json = {
17
+ 'user' => {
18
+ 'content' => {
19
+ 'email' => row[2],
20
+ 'login' => row[2],
21
+ 'firstname' => row[0],
22
+ 'lastname' => row[1],
23
+
24
+ # Following lines are ugly hack
25
+ 'role' => row[6],
26
+ 'password' => row[3],
27
+ 'domain' => row[9],
28
+
29
+ # And following lines are even much more ugly hack
30
+ # 'sso_provider' => '',
31
+ # 'authentication_modes' => ['sso', 'password']
32
+ },
33
+ 'meta' => {}
34
+ }
35
+ }
36
+
37
+ GoodData::Membership.new(json)
38
+ end
39
+ end
40
+
14
41
  describe '#[]' do
15
42
  it 'Accepts :all parameter' do
16
- pending 'Investigate which credentials use'
17
-
18
- project = GoodData::Project[:all]
19
- project.should_not be_nil
20
- project.should be_a_kind_of(Array)
43
+ projects = GoodData::Project[:all]
44
+ projects.should_not be_nil
45
+ projects.should be_a_kind_of(Array)
21
46
  end
22
47
 
23
48
  it 'Returns project if ID passed' do
@@ -40,9 +65,9 @@ describe GoodData::Project do
40
65
 
41
66
  describe '#all' do
42
67
  it 'Returns all projects' do
43
- pending 'Investigate which credentials use'
44
-
45
- GoodData::Project.all
68
+ projects = GoodData::Project.all
69
+ projects.should_not be_nil
70
+ projects.should be_a_kind_of(Array)
46
71
  end
47
72
  end
48
73
 
@@ -73,14 +98,81 @@ describe GoodData::Project do
73
98
  end
74
99
  end
75
100
 
101
+ describe "#member" do
102
+ it 'Returns GoodData::Membership when looking for existing user using email' do
103
+ project = ProjectHelper.get_default_project
104
+ res = project.member('svarovsky+gem_tester@gooddata.com')
105
+ expect(res).to be_instance_of(GoodData::Membership)
106
+ end
107
+
108
+ it 'Returns GoodData::Membership when looking for existing user using URL' do
109
+ project = ProjectHelper.get_default_project
110
+ res = project.member(ConnectionHelper::DEFAULT_USER_URL)
111
+ expect(res).to be_instance_of(GoodData::Membership)
112
+ end
113
+
114
+ it 'Returns GoodData::Membership when looking for existing user using GoodData::Profile' do
115
+ project = ProjectHelper.get_default_project
116
+ user = project.members.first
117
+ res = project.member(user)
118
+ expect(res).to be_instance_of(GoodData::Membership)
119
+ end
120
+
121
+ it 'Returns null for non-existing user' do
122
+ project = ProjectHelper.get_default_project
123
+ res = project.member('jan.kokotko@gooddata.com')
124
+ res.should be_nil
125
+ end
126
+ end
127
+
128
+ describe "#member?" do
129
+ it 'Returns true when looking for existing user using email' do
130
+ project = ProjectHelper.get_default_project
131
+ res = project.member?('svarovsky+gem_tester@gooddata.com')
132
+ res.should be_true
133
+ end
134
+
135
+ it 'Returns true when looking for existing user using URL' do
136
+ project = ProjectHelper.get_default_project
137
+ res = project.member?(ConnectionHelper::DEFAULT_USER_URL)
138
+ res.should be_true
139
+ end
140
+
141
+ it 'Returns true when looking for existing user using GoodData::Profile' do
142
+ project = ProjectHelper.get_default_project
143
+ user = project.members.first
144
+ res = project.member?(user)
145
+ res.should be_true
146
+ end
147
+
148
+ it 'Returns false for non-existing user' do
149
+ project = ProjectHelper.get_default_project
150
+ res = project.member?('jan.kokotko@gooddata.com')
151
+ res.should be_false
152
+ end
153
+
154
+ it 'Returns true for existing user when using optional list' do
155
+ project = ProjectHelper.get_default_project
156
+ list = project.members
157
+ res = project.member?('svarovsky+gem_tester@gooddata.com', list)
158
+ res.should be_true
159
+ end
160
+
161
+ it 'Returns false for non-existing user when using optional list' do
162
+ project = ProjectHelper.get_default_project
163
+ list = []
164
+ res = project.member?('svarovsky+gem_tester@gooddata.com', list)
165
+ res.should be_false
166
+ end
167
+ end
168
+
76
169
  describe '#processes' do
77
170
  it 'Returns the processes' do
78
- pending 'Investigate which credentials to use'
79
171
 
80
172
  GoodData.project = ProjectHelper::PROJECT_ID
81
-
82
173
  proj = GoodData.project
83
- procs = proj.processes
174
+ processes = proj.processes
175
+ expect(processes).to be_a_kind_of(Array)
84
176
  end
85
177
  end
86
178
 
@@ -98,7 +190,6 @@ describe GoodData::Project do
98
190
 
99
191
  describe '#users' do
100
192
  it 'Returns array of GoodData::Users' do
101
- pending 'Investigate which credentials to use'
102
193
 
103
194
  project = GoodData::Project[ProjectHelper::PROJECT_ID]
104
195
 
@@ -110,7 +201,7 @@ describe GoodData::Project do
110
201
  expect(users).to be_instance_of(Array)
111
202
 
112
203
  users.each do |user|
113
- expect(user).to be_instance_of(GoodData::User)
204
+ expect(user).to be_instance_of(GoodData::Membership)
114
205
 
115
206
  roles = user.roles
116
207
  roles.should_not be_nil
@@ -140,4 +231,126 @@ describe GoodData::Project do
140
231
  end
141
232
  end
142
233
  end
234
+
235
+ describe '#users_create' do
236
+ it 'Creates new users' do
237
+ project = ProjectHelper.get_default_project
238
+
239
+ users = (0...10).map do |i|
240
+ num = rand(1e6)
241
+ login = "gemtest#{num}@gooddata.com"
242
+
243
+ json = {
244
+ 'user' => {
245
+ 'content' => {
246
+ 'email' => login,
247
+ 'login' => login,
248
+ 'firstname' => 'the',
249
+ 'lastname' => num.to_s,
250
+
251
+ # Following lines are ugly hack
252
+ 'role' => 'admin',
253
+ 'password' => 'password',
254
+ 'domain' => ConnectionHelper::DEFAULT_DOMAIN,
255
+
256
+ # And following lines are even much more ugly hack
257
+ # 'sso_provider' => '',
258
+ # 'authentication_modes' => ['sso', 'password']
259
+ },
260
+ 'meta' => {}
261
+ }
262
+ }
263
+
264
+ GoodData::Membership.new(json)
265
+ end
266
+
267
+ res = GoodData::Domain.users_create(users)
268
+
269
+ project.users_create(users)
270
+
271
+ expect(res).to be_an_instance_of(Array)
272
+ res.each do |r|
273
+ expect(r).to be_an_instance_of(GoodData::Profile)
274
+ r.delete
275
+ end
276
+ end
277
+ end
278
+
279
+ describe '#users_import' do
280
+ it 'Import users from CSV' do
281
+
282
+ project = GoodData::Project[ProjectHelper::PROJECT_ID]
283
+
284
+ new_users = load_users_from_csv
285
+
286
+ project.users_import(new_users)
287
+ end
288
+ end
289
+
290
+ describe '#set_user_roles' do
291
+ it 'Properly updates user roles as needed' do
292
+ project = ProjectHelper.get_default_project
293
+
294
+ project.set_user_roles(ConnectionHelper::DEFAULT_USERNAME, 'admin')
295
+ end
296
+ end
297
+
298
+ describe '#set_users_roles' do
299
+ it 'Properly updates user roles as needed for bunch of users' do
300
+ project = ProjectHelper.get_default_project
301
+
302
+ list = load_users_from_csv
303
+
304
+ # Create domain users
305
+ domain_users = GoodData::Domain.users_create(list, ConnectionHelper::DEFAULT_DOMAIN)
306
+ expect(domain_users.length).to equal(list.length)
307
+
308
+ # Create list with user, desired_roles hashes
309
+ domain_users.each_with_index do |user, index|
310
+ list[index] = {
311
+ :user => user,
312
+ :roles => list[index].json['user']['content']['role'].split(' ').map { |r| r.downcase }.sort
313
+ }
314
+ end
315
+
316
+ res = project.set_users_roles(list)
317
+ expect(res.length).to equal(list.length)
318
+ res.each do |update_result|
319
+ expect(update_result[:result]['projectUsersUpdateResult']['successful'][0]).to include(update_result[:user].uri)
320
+ end
321
+
322
+ domain_users.each do |user|
323
+ user.delete if user.email != ConnectionHelper::DEFAULT_USERNAME
324
+ end
325
+ end
326
+
327
+ it 'Properly updates user roles when user specified by email and :roles specified as array of string with role names' do
328
+ project = ProjectHelper.get_default_project
329
+
330
+ list = [
331
+ {
332
+ :user => ConnectionHelper::DEFAULT_USERNAME,
333
+ :roles => ['admin']
334
+ }
335
+ ]
336
+
337
+ res = project.set_users_roles(list)
338
+ expect(res.length).to equal(list.length)
339
+ end
340
+
341
+ it 'Properly updates user roles when user specified by email and :roles specified as string with role name' do
342
+ project = ProjectHelper.get_default_project
343
+
344
+ list = [
345
+ {
346
+ :user => ConnectionHelper::DEFAULT_USERNAME,
347
+ :roles => 'admin'
348
+ }
349
+ ]
350
+
351
+ res = project.set_users_roles(list)
352
+ expect(res.length).to equal(list.length)
353
+ end
354
+
355
+ end
143
356
  end
@@ -9,6 +9,13 @@ describe GoodData::Schedule, :broken => true do
9
9
  :cron => '2 2 2 2 *'
10
10
  }
11
11
 
12
+ TEST_DATA_WITH_OPTIONAL_PARAM = {
13
+ :timezone => 'UTC',
14
+ :cron => '2 2 2 2 *',
15
+ :reschedule => 15
16
+ }
17
+
18
+
12
19
  TEST_PROCESS_ID = 'f12975d2-5958-4248-9c3d-4c8f2e1f067d'
13
20
 
14
21
  SCHEDULE_ID = '53642303e4b0ae3190e464a8'
@@ -72,6 +79,16 @@ describe GoodData::Schedule, :broken => true do
72
79
  sched.delete
73
80
  end
74
81
 
82
+ it 'Creates new schedule if mandatory params passed and optional params are present' do
83
+ sched = nil
84
+ expect {
85
+ sched = GoodData::Schedule.create(TEST_PROCESS_ID, TEST_CRON, @project_executable, TEST_DATA_WITH_OPTIONAL_PARAM)
86
+ }.not_to raise_error
87
+
88
+ sched.should_not be_nil
89
+ sched.delete
90
+ end
91
+
75
92
  it 'Throws exception when no process ID specified' do
76
93
  expect {
77
94
  sched = GoodData::Schedule.create(nil, TEST_CRON, @project_executable, TEST_DATA)
@@ -489,4 +506,45 @@ describe GoodData::Schedule, :broken => true do
489
506
  expect(@schedule.dirty).to eq(true)
490
507
  end
491
508
  end
509
+
510
+ describe '#reschedule' do
511
+ before(:each) do
512
+ @schedule = GoodData::Schedule.create(TEST_PROCESS_ID, TEST_CRON, @project_executable, TEST_DATA_WITH_OPTIONAL_PARAM)
513
+ end
514
+
515
+ after(:each) do
516
+ @schedule.delete
517
+ end
518
+
519
+ it 'Should return reschedule as integer' do
520
+ res = @schedule.reschedule
521
+ res.should_not be_nil
522
+ res.should_not be_empty
523
+ res.should be_a_kind_of(Integer)
524
+ end
525
+
526
+
527
+
528
+ end
529
+
530
+ describe '#reschedule=' do
531
+ before(:each) do
532
+ @schedule = GoodData::Schedule.create(TEST_PROCESS_ID, TEST_CRON, @project_executable, TEST_DATA_WITH_OPTIONAL_PARAM)
533
+ end
534
+
535
+ after(:each) do
536
+ @schedule.delete
537
+ end
538
+
539
+ it 'Assigns the reschedule and marks the object dirty' do
540
+ test_reschedule = 45
541
+
542
+ @schedule.reschedule = test_reschedule
543
+ expect(@schedule.reschedule).to eq(test_reschedule)
544
+ expect(@schedule.dirty).to eq(true)
545
+ end
546
+ end
547
+
548
+
549
+
492
550
  end