gooddata 1.0.2-java → 1.1.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/CONTRIBUTING.md +12 -0
  4. data/README.md +5 -2
  5. data/Rakefile +0 -1
  6. data/dev-gooddata-sso.pub.encrypted +40 -0
  7. data/gooddata.gemspec +3 -3
  8. data/lib/gooddata/connection.rb +23 -13
  9. data/lib/gooddata/helpers/data_helper.rb +0 -1
  10. data/lib/gooddata/lcm/actions/apply_custom_maql.rb +8 -1
  11. data/lib/gooddata/lcm/actions/associate_clients.rb +8 -1
  12. data/lib/gooddata/lcm/actions/base_action.rb +10 -0
  13. data/lib/gooddata/lcm/actions/collect_ca_metrics.rb +7 -1
  14. data/lib/gooddata/lcm/actions/collect_client_projects.rb +3 -0
  15. data/lib/gooddata/lcm/actions/collect_clients.rb +3 -1
  16. data/lib/gooddata/lcm/actions/collect_data_product.rb +10 -2
  17. data/lib/gooddata/lcm/actions/collect_dynamic_schedule_params.rb +12 -1
  18. data/lib/gooddata/lcm/actions/collect_ldm_objects.rb +6 -2
  19. data/lib/gooddata/lcm/actions/collect_meta.rb +1 -1
  20. data/lib/gooddata/lcm/actions/collect_segment_clients.rb +8 -1
  21. data/lib/gooddata/lcm/actions/collect_segments.rb +6 -5
  22. data/lib/gooddata/lcm/actions/collect_tagged_objects.rb +1 -1
  23. data/lib/gooddata/lcm/actions/collect_users_brick_users.rb +10 -4
  24. data/lib/gooddata/lcm/actions/create_segment_masters.rb +12 -2
  25. data/lib/gooddata/lcm/actions/ensure_data_product.rb +10 -0
  26. data/lib/gooddata/lcm/actions/ensure_technical_users_domain.rb +5 -1
  27. data/lib/gooddata/lcm/actions/ensure_technical_users_project.rb +3 -0
  28. data/lib/gooddata/lcm/actions/execute_schedules.rb +10 -0
  29. data/lib/gooddata/lcm/actions/import_object_collections.rb +1 -1
  30. data/lib/gooddata/lcm/actions/provision_clients.rb +12 -2
  31. data/lib/gooddata/lcm/actions/purge_clients.rb +2 -0
  32. data/lib/gooddata/lcm/actions/rename_existing_client_projects.rb +3 -0
  33. data/lib/gooddata/lcm/actions/synchronize_attribute_drillpaths.rb +4 -1
  34. data/lib/gooddata/lcm/actions/synchronize_cas.rb +7 -1
  35. data/lib/gooddata/lcm/actions/synchronize_clients.rb +11 -1
  36. data/lib/gooddata/lcm/actions/synchronize_color_palette.rb +7 -1
  37. data/lib/gooddata/lcm/actions/synchronize_etls_in_segment.rb +12 -7
  38. data/lib/gooddata/lcm/actions/synchronize_label_types.rb +4 -1
  39. data/lib/gooddata/lcm/actions/synchronize_ldm.rb +18 -7
  40. data/lib/gooddata/lcm/actions/synchronize_meta.rb +9 -0
  41. data/lib/gooddata/lcm/actions/synchronize_new_segments.rb +11 -1
  42. data/lib/gooddata/lcm/actions/synchronize_processes.rb +7 -1
  43. data/lib/gooddata/lcm/actions/synchronize_schedules.rb +4 -1
  44. data/lib/gooddata/lcm/actions/synchronize_tag_objects.rb +6 -0
  45. data/lib/gooddata/lcm/actions/synchronize_user_filters.rb +60 -15
  46. data/lib/gooddata/lcm/actions/synchronize_user_groups.rb +7 -1
  47. data/lib/gooddata/lcm/actions/synchronize_users.rb +106 -3
  48. data/lib/gooddata/lcm/actions/update_release_table.rb +19 -0
  49. data/lib/gooddata/lcm/helpers/check_helper.rb +21 -6
  50. data/lib/gooddata/lcm/lcm2.rb +35 -22
  51. data/lib/gooddata/lcm/types/class/gd_logger.rb +23 -0
  52. data/lib/gooddata/lcm/types/class/gd_product.rb +23 -0
  53. data/lib/gooddata/lcm/types/class/gd_project.rb +23 -0
  54. data/lib/gooddata/lcm/types/class/smart_hash.rb +23 -0
  55. data/lib/gooddata/lcm/types/complex/segment.rb +1 -1
  56. data/lib/gooddata/lcm/types/scalar/integer.rb +2 -2
  57. data/lib/gooddata/lcm/types/special/any.rb +18 -0
  58. data/lib/gooddata/models/blueprint/dataset_blueprint.rb +1 -1
  59. data/lib/gooddata/models/blueprint/to_manifest.rb +1 -3
  60. data/lib/gooddata/models/blueprint/to_wire.rb +2 -1
  61. data/lib/gooddata/models/from_wire.rb +13 -1
  62. data/lib/gooddata/models/metadata/folder.rb +22 -0
  63. data/lib/gooddata/models/metadata/metric.rb +5 -8
  64. data/lib/gooddata/models/model.rb +1 -1
  65. data/lib/gooddata/models/process.rb +42 -32
  66. data/lib/gooddata/models/project.rb +19 -36
  67. data/lib/gooddata/models/project_creator.rb +3 -1
  68. data/lib/gooddata/models/project_role.rb +3 -4
  69. data/lib/gooddata/models/schedule.rb +0 -2
  70. data/lib/gooddata/models/user_filters/mandatory_user_filter.rb +9 -1
  71. data/lib/gooddata/models/user_filters/user_filter.rb +1 -2
  72. data/lib/gooddata/models/user_filters/user_filter_builder.rb +18 -6
  73. data/lib/gooddata/rest/client.rb +1 -2
  74. data/lib/gooddata/rest/connection.rb +12 -46
  75. data/lib/gooddata/rest/phmap.rb +101 -56
  76. data/lib/gooddata/version.rb +1 -1
  77. data/rubydev_public.gpg.encrypted +51 -0
  78. data/rubydev_secret_keys.gpg.encrypted +109 -0
  79. data/spec/data/user_filters.csv +2 -0
  80. data/spec/environment/default.rb +2 -2
  81. data/spec/environment/development.rb +1 -1
  82. data/spec/environment/staging.rb +2 -3
  83. data/spec/environment/testing.rb +4 -4
  84. data/spec/integration/connection_spec.rb +37 -0
  85. data/spec/integration/core/connection_spec.rb +1 -1
  86. data/spec/integration/core/logging_spec.rb +8 -6
  87. data/spec/integration/core/project_spec.rb +1 -1
  88. data/spec/integration/mandatory_user_filter_spec.rb +53 -0
  89. data/spec/integration/mixins/id_to_uri_spec.rb +17 -5
  90. data/spec/integration/models/label_spec.rb +9 -0
  91. data/spec/integration/models/metric_spec.rb +24 -0
  92. data/spec/integration/models/process_spec.rb +35 -0
  93. data/spec/integration/models/project_role_spec.rb +1 -1
  94. data/spec/integration/models/schedule_spec.rb +0 -8
  95. data/spec/integration/schedule_spec.rb +4 -6
  96. data/spec/integration/user_filters_spec.rb +20 -16
  97. data/spec/integration/user_group_spec.rb +1 -1
  98. data/spec/integration/vcr_cassettes/GoodData_-_logging/_logger/can_assign_a_custom_logger.yml +2287 -0
  99. data/spec/integration/vcr_cassettes/GoodData_-_logging/_logger/client_logs_when_given_custom_message.yml +2287 -0
  100. data/spec/integration/vcr_cassettes/GoodData_-_logging/_logger/has_the_request_id_logged_when_I_passed_it.yml +2287 -0
  101. data/spec/integration/vcr_cassettes/GoodData_-_logging/_logging_off/Disables_logging.yml +2287 -0
  102. data/spec/integration/vcr_cassettes/GoodData_-_logging/_logging_on/Enables_logging.yml +2287 -0
  103. data/spec/integration/vcr_cassettes/GoodData_-_project/_project/Returns_project_assigned.yml +354 -0
  104. data/spec/integration/vcr_cassettes/GoodData_-_project/_project_/Assigns_nil.yml +299 -0
  105. data/spec/integration/vcr_cassettes/GoodData_-_project/_project_/Assigns_project_directly.yml +354 -0
  106. data/spec/integration/vcr_cassettes/GoodData_-_project/_project_/Assigns_project_using_project_ID.yml +354 -0
  107. data/spec/integration/vcr_cassettes/GoodData_-_project/_project_/Assigns_project_using_project_URL.yml +354 -0
  108. data/spec/integration/vcr_cassettes/GoodData_-_project/_with_project/Uses_project_specified.yml +354 -0
  109. data/spec/integration/vcr_cassettes/GoodData_Metric/all.yml +2065 -0
  110. data/spec/integration/vcr_cassettes/GoodData_Metric/should_be_able_to_update_folders.yml +119 -0
  111. data/spec/integration/vcr_cassettes/GoodData_Mixin_MdIdToUri/all.yml +9812 -0
  112. data/spec/integration/vcr_cassettes/GoodData_Mixin_MdIdToUri/should_get_json_containing_correct_id.yml +174 -0
  113. data/spec/integration/vcr_cassettes/GoodData_Mixin_MdIdToUri/should_return_nil_for_unknown_id.yml +58 -0
  114. data/spec/integration/vcr_cassettes/GoodData_Mixin_MdIdToUri/should_throw_BadRequest_for_-1.yml +63 -0
  115. data/spec/integration/vcr_cassettes/GoodData_Rest_Connection/_connect/Connects_using_username_and_password.yml +299 -0
  116. data/spec/integration/vcr_cassettes/GoodData_Rest_Connection/_disconnect/Connects_using_username_and_password.yml +299 -0
  117. data/spec/integration/vcr_cassettes/GoodData_Rest_Connection/_generate_request_id/Generates_a_non-empty_string.yml +2287 -0
  118. data/spec/integration/vcr_cassettes/GoodData_UserGroup/_/Should_list_user_groups_as_Array.yml +56 -0
  119. data/spec/integration/vcr_cassettes/GoodData_UserGroup/_add_members/Should_add_member.yml +315 -0
  120. data/spec/integration/vcr_cassettes/GoodData_UserGroup/_members/Should_return_members_as_array.yml +54 -0
  121. data/spec/integration/vcr_cassettes/GoodData_UserGroup/_remove_members/Should_remove_existing_members.yml +258 -0
  122. data/spec/integration/vcr_cassettes/GoodData_UserGroup/_save/updates_existing_group.yml +159 -0
  123. data/spec/integration/vcr_cassettes/GoodData_UserGroup/_set_members/Should_set_new_members.yml +158 -0
  124. data/spec/integration/vcr_cassettes/GoodData_UserGroup/all.yml +809 -0
  125. data/spec/spec_helper.rb +46 -2
  126. data/spec/unit/actions/associate_clients_spec.rb +2 -1
  127. data/spec/unit/actions/collect_data_product_spec.rb +3 -1
  128. data/spec/unit/actions/collect_segment_clients_spec.rb +1 -0
  129. data/spec/unit/actions/create_segment_masters_spec.rb +1 -0
  130. data/spec/unit/actions/ensure_data_product_spec.rb +1 -0
  131. data/spec/unit/actions/ensure_technical_users_domain_spec.rb +2 -0
  132. data/spec/unit/actions/ensure_technical_users_project_spec.rb +4 -0
  133. data/spec/unit/actions/provision_clients_spec.rb +2 -1
  134. data/spec/unit/actions/synchronize_etls_in_segment_spec.rb +0 -6
  135. data/spec/unit/actions/synchronize_ldm_spec.rb +20 -7
  136. data/spec/unit/actions/synchronize_user_filters_spec.rb +21 -0
  137. data/spec/unit/helpers/check_helper_production_spec.rb +34 -0
  138. data/spec/unit/helpers/check_helper_spec.rb +97 -9
  139. data/spec/unit/lcm/lcm2_spec.rb +67 -3
  140. data/spec/unit/models/blueprint/to_wire_spec.rb +1 -0
  141. data/spec/unit/models/dataset_blueprint.rb +14 -0
  142. data/spec/unit/models/from_wire_spec.rb +20 -0
  143. data/spec/unit/models/model_spec.rb +10 -0
  144. data/spec/unit/models/to_manifest_spec.rb +29 -0
  145. data/spec/unit/models/user_filters/user_filter_builder_spec.rb +44 -6
  146. data/spec/unit/rest/phmap_spec.rb +117 -0
  147. data/spec/vcr_configurer.rb +63 -0
  148. metadata +283 -24
  149. data/lib/gooddata/lcm/actions/ensure_segments.rb +0 -32
@@ -6,16 +6,29 @@
6
6
 
7
7
  require 'gooddata/lcm/lcm2'
8
8
 
9
+ shared_examples 'a smart hash' do
10
+ let(:expected_value) { 'bar' }
11
+ it 'fetches value' do
12
+ expect(subject.FOO).to eq(expected_value)
13
+ expect(subject.foo).to eq(expected_value)
14
+ expect(subject['FOO']).to eq(expected_value)
15
+ expect(subject['foo']).to eq(expected_value)
16
+ expect(subject[:FOO]).to eq(expected_value)
17
+ expect(subject[:foo]).to eq(expected_value)
18
+ end
19
+ end
20
+
9
21
  describe 'GoodData::LCM2' do
10
22
  describe '#skip_actions' do
11
23
  let(:client) { double(:client) }
12
- let(:domain) { double(:domain) }
13
- let(:logger) { double(:logger) }
24
+ let(:domain) { 'domain' }
25
+ let(:logger) { GoodData.logger }
14
26
  let(:params) do
15
27
  params = {
16
28
  skip_actions: %w(CollectSegments SynchronizeUsers),
17
29
  GDC_GD_CLIENT: client,
18
- GDC_LOGGER: logger
30
+ GDC_LOGGER: logger,
31
+ domain: domain
19
32
  }
20
33
  GoodData::LCM2.convert_to_smart_hash(params)
21
34
  end
@@ -33,4 +46,55 @@ describe 'GoodData::LCM2' do
33
46
  GoodData::LCM2.perform('users', params)
34
47
  end
35
48
  end
49
+
50
+ describe '#convert_to_smart_hash' do
51
+ subject do
52
+ GoodData::LCM2.convert_to_smart_hash(hash)
53
+ end
54
+
55
+ let(:hash) { { fooBarBaz: 'qUx' } }
56
+
57
+ it 'keeps letter case' do
58
+ expect(subject.to_h).to eq(hash)
59
+ end
60
+
61
+ context 'when hash contains symbol key in lower-case' do
62
+ it_behaves_like 'a smart hash' do
63
+ let(:hash) { { foo: 'bar' } }
64
+ end
65
+ end
66
+
67
+ context 'when hash contains string key in lower-case' do
68
+ it_behaves_like 'a smart hash' do
69
+ let(:hash) { { 'foo' => 'bar' } }
70
+ end
71
+ end
72
+
73
+ context 'when hash contains symbol key in upper-case' do
74
+ it_behaves_like 'a smart hash' do
75
+ let(:hash) { { FOO: 'bar' } }
76
+ end
77
+ end
78
+
79
+ context 'when hash contains string key in upper-case' do
80
+ it_behaves_like 'a smart hash' do
81
+ let(:hash) { { 'FOO' => 'bar' } }
82
+ end
83
+ end
84
+ end
85
+
86
+ describe '#run_action' do
87
+ let(:params) { double('params') }
88
+ let(:logger) { GoodData.logger }
89
+ it 'runs the action' do
90
+ expect(params).to receive(:clear_filters).exactly(2).times
91
+ expect(params).to receive(:segments_filter)
92
+ expect(params).to receive(:data_product)
93
+ expect(params).to receive(:gdc_logger) { logger }
94
+ expect(params).to receive(:setup_filters)
95
+
96
+ expect(GoodData::LCM2::CollectSegments).to receive(:call)
97
+ GoodData::LCM2.run_action(GoodData::LCM2::CollectSegments, params)
98
+ end
99
+ end
36
100
  end
@@ -146,6 +146,7 @@ describe GoodData::Model::ProjectBlueprint do
146
146
  result = ToWire.fact_to_wire(nil, fact_def)
147
147
  expect(result).to eq(
148
148
  fact: {
149
+ type: "fact",
149
150
  identifier: "fact.stage_history.stage_velocity",
150
151
  title: "Stage Velocity",
151
152
  dataType: "DECIMAL(12,2)",
@@ -0,0 +1,14 @@
1
+ describe GoodData::Model::DatasetBlueprint do
2
+ let(:dataset) do
3
+ { columns: [{ type: 'hll' },
4
+ { type: 'fact' },
5
+ { type: 'date_fact' }] }
6
+ end
7
+ subject { GoodData::Model::DatasetBlueprint }
8
+ describe '.facts' do
9
+ it 'returns facts of supported types' do
10
+ result = subject.facts(dataset)
11
+ expect(result).to eq(dataset[:columns])
12
+ end
13
+ end
14
+ end
@@ -233,6 +233,26 @@ describe GoodData::Model::FromWire do
233
233
  }
234
234
  ])
235
235
  end
236
+
237
+ it 'supports hll' do
238
+ model = @model_view['projectModelView']['model']['projectModel']['datasets'].first
239
+ hll_fact = { "fact" => {
240
+ "identifier" => "hll_test",
241
+ "title" => "Test HLL Fact",
242
+ "dataType" => "HLL",
243
+ 'type' => 'hll'
244
+ } }
245
+ model['dataset']['facts'] << hll_fact
246
+ expected = {
247
+ type: :hll,
248
+ id: "hll_test",
249
+ title: "Test HLL Fact",
250
+ gd_data_type: "HLL",
251
+ folder: nil
252
+ }
253
+ facts = GoodData::Model::FromWire.parse_facts(model)
254
+ expect(facts).to include(expected)
255
+ end
236
256
  end
237
257
 
238
258
  describe '#parse_dataset' do
@@ -74,4 +74,14 @@ describe GoodData::Model do
74
74
  @base_blueprint.merge!(@additional_blueprint)
75
75
  @base_blueprint.find_dataset("dataset.repos").attributes.include?(type: "attribute", id: "some_attr_id", :title => "Repository Name")
76
76
  end
77
+
78
+ describe '.check_gd_data_type' do
79
+ let(:hll_types) { %w(HLL hll hLl) }
80
+ it 'supports HLL type' do
81
+ hll_types.each do |type|
82
+ actual = subject.check_gd_data_type(type)
83
+ expect(actual).to be(true)
84
+ end
85
+ end
86
+ end
77
87
  end
@@ -18,6 +18,35 @@ describe GoodData::Model::ToManifest do
18
18
  expect(ToManifest.to_manifest(@spec)).to eq @result
19
19
  end
20
20
 
21
+ context 'when HLL fact is in the spec' do
22
+ let(:hll_fact) do
23
+ {
24
+ type: "hll",
25
+ id: 'fact.commits.lines_added',
26
+ column_name: 'lines_added',
27
+ title: 'Lines Added'
28
+ }
29
+ end
30
+
31
+ let(:spec) do
32
+ hll_spec = @spec
33
+ hll_spec[:datasets]
34
+ .find { |d| d[:id] == 'dataset.commits' }[:columns] << hll_fact
35
+ hll_spec
36
+ end
37
+
38
+ it "converts the HLL fact to manifest" do
39
+ actual = ToManifest.to_manifest(spec)
40
+ expected = {
41
+ 'populates' => ['fact.commits.lines_added'],
42
+ 'mode' => 'FULL',
43
+ 'columnName' => 'lines_added'
44
+ }
45
+ parts = actual[2]['dataSetSLIManifest']['parts']
46
+ expect(parts).to include(expected)
47
+ end
48
+ end
49
+
21
50
  it 'blueprint can be set with date reference and default format is set' do
22
51
  blueprint = GoodData::Model::ProjectBlueprint.build("my_bp") do |p|
23
52
  p.add_date_dimension("committed_on")
@@ -4,6 +4,14 @@
4
4
  # This source code is licensed under the BSD-style license found in the
5
5
  # LICENSE file in the root directory of this source tree.
6
6
 
7
+ shared_examples 'a user filter deleter' do
8
+ it 'deletes the filter' do
9
+ expect(existing_filter).to receive(:delete)
10
+ result = subject.execute_mufs(filter_definitions, options)
11
+ expect(result[:deleted].length).to be(1)
12
+ end
13
+ end
14
+
7
15
  describe GoodData::UserFilterBuilder do
8
16
  describe '.execute_mufs' do
9
17
  let(:login) { 'rubydev+admin@gooddata.com' }
@@ -63,10 +71,29 @@ describe GoodData::UserFilterBuilder do
63
71
  end
64
72
 
65
73
  it 'resolves mufs to be created/deleted' do
66
- expect(existing_filter).to receive(:delete)
74
+ expect(existing_filter).to_not receive(:delete)
67
75
  result = subject.execute_mufs(filter_definitions, options)
68
76
  expect(result[:created].length).to be(1)
69
- expect(result[:deleted].length).to be(1)
77
+ expect(result[:deleted].length).to be(0)
78
+ end
79
+
80
+ context 'when dry_run option set to true' do
81
+ let(:options) do
82
+ { client: client,
83
+ project: project,
84
+ dry_run: true }
85
+ end
86
+
87
+ it 'does not alter filters' do
88
+ expect(client).not_to receive(:post)
89
+ subject.execute_mufs(filter_definitions, options)
90
+ end
91
+
92
+ it 'returns results' do
93
+ result = subject.execute_mufs(filter_definitions, options)
94
+ expected = [{ status: 'dry_run', user: nil, type: 'create' }]
95
+ expect(result[:results]).to eq(expected)
96
+ end
70
97
  end
71
98
 
72
99
  context 'when users_brick_input option specified' do
@@ -88,10 +115,10 @@ describe GoodData::UserFilterBuilder do
88
115
  allow(existing_filter).to receive(:json)
89
116
  .and_return(related: profile_url)
90
117
  end
91
- it 'deletes the filter' do
92
- expect(existing_filter).to receive(:delete)
93
- result = subject.execute_mufs(filter_definitions, options)
94
- expect(result[:deleted].length).to be(1)
118
+ it_behaves_like 'a user filter deleter'
119
+ context 'when users_brick_input has symbols as keys' do
120
+ let(:users_brick_input) { [{ login: login }] }
121
+ it_behaves_like 'a user filter deleter'
95
122
  end
96
123
  end
97
124
 
@@ -107,5 +134,16 @@ describe GoodData::UserFilterBuilder do
107
134
  end
108
135
  end
109
136
  end
137
+
138
+ context 'when creating MUFs results in errors' do
139
+ before do
140
+ allow(client).to receive(:post)
141
+ .and_return 'userFiltersUpdateResult' => { 'failed' => [{ status: :failed }] }
142
+ end
143
+
144
+ it 'fails' do
145
+ expect { subject.execute_mufs(filter_definitions, options) }.to raise_error(/Creating MUFs resulted in errors/)
146
+ end
147
+ end
110
148
  end
111
149
  end
@@ -0,0 +1,117 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
4
+ # This source code is licensed under the BSD-style license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ require 'gooddata/rest/phmap'
8
+
9
+ PlaceholderExample = Struct.new(:name, :title, :mapped)
10
+
11
+ describe GoodData::Rest::Connection do
12
+ [
13
+ PlaceholderExample.new('execute', '/gdc/projects/uif55z7zg9zunnsffsqu6nzyg38j20qg/execute', '/gdc/projects/{id}/execute'),
14
+
15
+ PlaceholderExample.new('outputStage', '/gdc/dataload/projects/uif55z7zg9zunnsffsqu6nzyg38j20qg/outputStage', '/gdc/dataload/projects/{id}/outputStage'),
16
+
17
+ PlaceholderExample.new('datawarehouse instance', '/gdc/datawarehouse/instances/c90ef89f07978760523dd409165c71f3', '/gdc/datawarehouse/instances/{id}'),
18
+ PlaceholderExample.new('datawarehouse execution', '/gdc/datawarehouse/executions/exec123', '/gdc/datawarehouse/executions/{id}'),
19
+
20
+ PlaceholderExample.new('dataproduct client segment', '/gdc/domains/stg2-lcm-prod/dataproducts/MY-DP/clients?segment=MY-SEG4',
21
+ '/gdc/domains/{id}/dataproducts/{data_product}/clients?segment={segment}'),
22
+ PlaceholderExample.new('dataproduct client', '/gdc/domains/MY_DOMAIN3/dataproducts/4_7-prod/clients/some-client1',
23
+ '/gdc/domains/{id}/dataproducts/{data_product}/clients/{client}'),
24
+ PlaceholderExample.new('dataproduct clients', '/gdc/domains/D_-3/dataproducts/DP_1-/clients', '/gdc/domains/{id}/dataproducts/{data_product}/clients'),
25
+
26
+ PlaceholderExample.new('synchronizeClients result details', '/gdc/domains/d2/dataproducts/dp-6/segments/seg_1/synchronizeClients/results/_-res8/details?offset=0&limit=1000',
27
+ '/gdc/domains/{id}/dataproducts/{data_product}/segments/{segment}/synchronizeClients/results/{result}/details?offset={offset}&limit={limit}'),
28
+ PlaceholderExample.new('synchronizeClients result', '/gdc/domains/D/dataproducts/DP/segments/SEG/synchronizeClients/results/RES',
29
+ '/gdc/domains/{id}/dataproducts/{data_product}/segments/{segment}/synchronizeClients/results/{result}'),
30
+ PlaceholderExample.new('dataproduct segment', '/gdc/domains/D/dataproducts/DP/segments/SEG', '/gdc/domains/{id}/dataproducts/{data_product}/segments/{segment}'),
31
+ PlaceholderExample.new('dataproduct segments', '/gdc/domains/D/dataproducts/DP/segments', '/gdc/domains/{id}/dataproducts/{data_product}/segments'),
32
+
33
+ PlaceholderExample.new('provisionClientProjects result details', '/gdc/domains/D/dataproducts/DP/provisionClientProjects/results/RES/details?offset=7&limit=50',
34
+ '/gdc/domains/{id}/dataproducts/{data_product}/provisionClientProjects/results/{result}/details?offset={offset}&limit={limit}'),
35
+ PlaceholderExample.new('provisionClientProjects result', '/gdc/domains/D/dataproducts/DP/provisionClientProjects/results/RES',
36
+ '/gdc/domains/{id}/dataproducts/{data_product}/provisionClientProjects/results/{result}'),
37
+ PlaceholderExample.new('provisionClientProjects', '/gdc/domains/D/dataproducts/DP/provisionClientProjects',
38
+ '/gdc/domains/{id}/dataproducts/{data_product}/provisionClientProjects'),
39
+ PlaceholderExample.new('updateClients delet extra', '/gdc/domains/D/dataproducts/DP/updateClients?deleteExtraInSegments=SEG',
40
+ '/gdc/domains/{id}/dataproducts/{data_product}/updateClients?deleteExtraInSegments={segments}'),
41
+ PlaceholderExample.new('updateClients', '/gdc/domains/D/dataproducts/DP/updateClients', '/gdc/domains/{id}/dataproducts/{data_product}/updateClients'),
42
+
43
+ PlaceholderExample.new('domain dataproducts', '/gdc/domains/D/dataproducts/DP', '/gdc/domains/{id}/dataproducts/{data_product}'),
44
+ PlaceholderExample.new('domain dataproducts', '/gdc/domains/D/dataproducts', '/gdc/domains/{id}/dataproducts'),
45
+
46
+ PlaceholderExample.new('segment synchronizeClients result details', '/gdc/domains/D/segments/SEG/synchronizeClients/results/RES/details?offset=0&limit=100',
47
+ '/gdc/domains/{id}/segments/{segment}/synchronizeClients/results/{result}/details?offset={offset}&limit={limit}'),
48
+ PlaceholderExample.new('segment synchronizeClients result', '/gdc/domains/D/segments/SEG/synchronizeClients/results/RES',
49
+ '/gdc/domains/{id}/segments/{segment}/synchronizeClients/results/{result}'),
50
+ PlaceholderExample.new('domain segment', '/gdc/domains/D/segments/SEG/', '/gdc/domains/{id}/segments/{segment}/'),
51
+ PlaceholderExample.new('domain segment', '/gdc/domains/D/segments/SEG', '/gdc/domains/{id}/segments/{segment}'),
52
+
53
+ PlaceholderExample.new('domain client segment', '/gdc/domains/D/clients?segment=SEG', '/gdc/domains/{id}/clients?segment={segment}'),
54
+ PlaceholderExample.new('client settings title', '/gdc/domains/D/clients/C/settings/lcm.title', '/gdc/domains/{id}/clients/{client_id}/settings/lcm.title'),
55
+ PlaceholderExample.new('client settings token', '/gdc/domains/D/clients/C/settings/lcm.token', '/gdc/domains/{id}/clients/{client_id}/settings/lcm.token'),
56
+ PlaceholderExample.new('domain client', '/gdc/domains/D/clients/C', '/gdc/domains/{id}/clients/{client_id}'),
57
+ PlaceholderExample.new('domain provisionClientProjects result details', '/gdc/domains/D/provisionClientProjects/results/R/details?offset=0&limit=100',
58
+ '/gdc/domains/{id}/provisionClientProjects/results/{result}/details?offset={offset}&limit={limit}'),
59
+ PlaceholderExample.new('domain provisionClientProjects result', '/gdc/domains/D/provisionClientProjects/results/R',
60
+ '/gdc/domains/{id}/provisionClientProjects/results/{result}'),
61
+ PlaceholderExample.new('domain provisionClientProjects', '/gdc/domains/D/provisionClientProjects', '/gdc/domains/{id}/provisionClientProjects'),
62
+ PlaceholderExample.new('domain updateClients', '/gdc/domains/D/updateClients', '/gdc/domains/{id}/updateClients'),
63
+ PlaceholderExample.new('domain', '/gdc/domains/D/', '/gdc/domains/{id}/'),
64
+
65
+ PlaceholderExample.new('exporter result', '/gdc/exporter/result/a23f/c56', '/gdc/exporter/result/{id}/{id}'),
66
+
67
+ PlaceholderExample.new('syncProcesses task', '/gdc/internal/lcm/domains/D/dataproducts/DP/segments/SEG/syncProcesses/P',
68
+ '/gdc/internal/lcm/domains/{id}/dataproducts/{data_product}/segments/{segment}/syncProcesses/{process}'),
69
+ PlaceholderExample.new('syncProcesses', '/gdc/internal/lcm/domains/D/dataproducts/DP/segments/SEG/syncProcesses',
70
+ '/gdc/internal/lcm/domains/{id}/dataproducts/{data_product}/segments/{segment}/syncProcesses'),
71
+
72
+ PlaceholderExample.new('setPermissions', '/gdc/internal/projects/PID/objects/setPermissions', '/gdc/internal/projects/{id}/objects/setPermissions'),
73
+
74
+ PlaceholderExample.new('md variable', '/gdc/md/PID/variables/item/54', '/gdc/md/{id}/variables/item/{id}'),
75
+ PlaceholderExample.new('md validate task', '/gdc/md/PID/validate/task/some-task56', '/gdc/md/{id}/validate/task/{id}'),
76
+ PlaceholderExample.new('md using', '/gdc/md/PID/using2/456/980', '/gdc/md/{id}/using2/{id}/{id}'),
77
+ PlaceholderExample.new('md using', '/gdc/md/PID/using2/456', '/gdc/md/{id}/using2/{id}'),
78
+ PlaceholderExample.new('md userfilters user', '/gdc/md/PID/userfilters?users=/gdc/account/profile/rubydev+admin@goo', '/gdc/md/{id}/userfilters?users={users}'),
79
+ PlaceholderExample.new('md userfilters', '/gdc/md/PID/userfilters?count=1&offset=5', '/gdc/md/{id}/userfilters?count={count}&offset={offset}'),
80
+ PlaceholderExample.new('md usedby', '/gdc/md/PID/usedby2/4/5', '/gdc/md/{id}/usedby2/{id}/{id}'),
81
+ PlaceholderExample.new('md usedby', '/gdc/md/PID/usedby2/4', '/gdc/md/{id}/usedby2/{id}'),
82
+ PlaceholderExample.new('md task status', '/gdc/md/PID/tasks/567/status', '/gdc/md/{id}/tasks/{id}/status'),
83
+ PlaceholderExample.new('md validElements', '/gdc/md/PID/obj/876/validElements', '/gdc/md/{id}/obj/{id}/validElements'),
84
+ PlaceholderExample.new('md elements', '/gdc/md/PID/obj/876/elements', '/gdc/md/{id}/obj/{id}/elements'),
85
+ PlaceholderExample.new('md obj', '/gdc/md/PID/obj/876', '/gdc/md/{id}/obj/{id}'),
86
+ PlaceholderExample.new('md etltaks', '/gdc/md/PID/etltask/567', '/gdc/md/{id}/etltask/{id}'),
87
+ PlaceholderExample.new('md dataResult', '/gdc/md/PID/dataResult/666', '/gdc/md/{id}/dataResult/{id}'),
88
+ PlaceholderExample.new('md', '/gdc/md/PID', '/gdc/md/{id}'),
89
+
90
+ PlaceholderExample.new('project user roles', '/gdc/projects/PID/users/UID/roles', '/gdc/projects/{id}/users/{id}/roles'),
91
+ PlaceholderExample.new('project user permissions', '/gdc/projects/PID/users/UID/permissions', '/gdc/projects/{id}/users/{id}/permissions'),
92
+ PlaceholderExample.new('project users', '/gdc/projects/PID/users', '/gdc/projects/{id}/users'),
93
+ PlaceholderExample.new('schedule execution', '/gdc/projects/PID/schedules/SCHED/executions/EX', '/gdc/projects/{id}/schedules/{id}/executions/{id}'),
94
+ PlaceholderExample.new('schedule', '/gdc/projects/PID/schedules/SCHED', '/gdc/projects/{id}/schedules/{id}'),
95
+ PlaceholderExample.new('project role', '/gdc/projects/PID/roles/555', '/gdc/projects/{id}/roles/{id}'),
96
+ PlaceholderExample.new('model view view', '/gdc/projects/PID/model/view/VIEW', '/gdc/projects/{id}/model/view/{id}'),
97
+ PlaceholderExample.new('model view', '/gdc/projects/PID/model/view', '/gdc/projects/{id}/model/view'),
98
+ PlaceholderExample.new('model diff diff', '/gdc/projects/PID/model/diff/DIFF', '/gdc/projects/{id}/model/diff/{id}'),
99
+ PlaceholderExample.new('model diff', '/gdc/projects/PID/model/diff', '/gdc/projects/{id}/model/diff'),
100
+ PlaceholderExample.new('dataload metadata', '/gdc/projects/PID/dataload/metadata/PID', '/gdc/projects/{id}/dataload/metadata/{project}'),
101
+ PlaceholderExample.new('dataload execution', '/gdc/projects/PID/dataload/processes/PRID/executions/EX', '/gdc/projects/{id}/dataload/processes/{id}/executions/{id}'),
102
+ PlaceholderExample.new('dataload process', '/gdc/projects/PID/dataload/processes/PRID', '/gdc/projects/{id}/dataload/processes/{id}'),
103
+ PlaceholderExample.new('project', '/gdc/projects/PID/', '/gdc/projects/{id}/'),
104
+ PlaceholderExample.new('project', '/gdc/projects/PID', '/gdc/projects/{id}'),
105
+
106
+ PlaceholderExample.new('userGroup', '/gdc/userGroups/GID', '/gdc/userGroups/{id}'),
107
+
108
+ PlaceholderExample.new('profile', '/gdc/account/profile/UID', '/gdc/account/profile/{id}'),
109
+ PlaceholderExample.new('login', '/gdc/account/login/UID', '/gdc/account/login/{id}'),
110
+ PlaceholderExample.new('domain user', '/gdc/account/domains/D/users?login=rubydev+admin@gooddata.com', '/gdc/account/domains/{id}/users?login={login}'),
111
+ PlaceholderExample.new('account domain', '/gdc/account/domains/D', '/gdc/account/domains/{id}')
112
+ ].each do |example|
113
+ it "should map placeholders in #{example.name} API" do
114
+ expect(GoodData::Rest::Connection.map_placeholders(example.title)).to eq(example.mapped)
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,63 @@
1
+ require 'vcr'
2
+ require 'active_support/core_ext/string'
3
+
4
+ module GoodData
5
+ module Helpers
6
+ # Configures VCR for integration tests
7
+ class VcrConfigurer
8
+ def self.name_to_placeholder(name)
9
+ "<#{name.underscore.upcase}>"
10
+ end
11
+
12
+ def self.filter_body_field(vcr_config, part, field)
13
+ placeholder = name_to_placeholder(field)
14
+ vcr_config.filter_sensitive_data(placeholder) do |interaction|
15
+ body_match = interaction[part].body.match(/"#{Regexp.quote(field)}":\s*"([^"]+)"/)
16
+ body_match.captures.first if body_match
17
+ end
18
+ end
19
+
20
+ def self.filter_header(vcr_config, part, header_name)
21
+ placeholder = name_to_placeholder(header_name)
22
+ vcr_config.filter_sensitive_data(placeholder) do |interaction|
23
+ header = interaction[part].headers[header_name]
24
+ header.first if header
25
+ end
26
+ end
27
+
28
+ # custom path matcher, sanitizing the randomness of uploads dirs
29
+ gdc_path_matcher = lambda do |client_request, recorded_request|
30
+ client_path = client_request.parsed_uri.path
31
+ recorded_path = recorded_request.parsed_uri.path
32
+ uploads_regex = %r{(\/gdc\/uploads\/)[^\/]+(\/.*)}
33
+ if client_path.match(uploads_regex) && recorded_path.match(uploads_regex)
34
+ client_path.gsub(uploads_regex, '\1UPLOADS_TMP\2') == recorded_path.gsub(uploads_regex, '\1UPLOADS_TMP\2')
35
+ else
36
+ client_path == recorded_path
37
+ end
38
+ end
39
+
40
+ VCR.configure do |vcr_config|
41
+ vcr_config.cassette_library_dir = 'spec/integration/vcr_cassettes'
42
+ vcr_config.hook_into :webmock
43
+ vcr_config.allow_http_connections_when_no_cassette = true
44
+ vcr_config.configure_rspec_metadata!
45
+
46
+ vcr_config.default_cassette_options = {
47
+ :decode_compressed_response => true,
48
+ :match_requests_on => [gdc_path_matcher, :method, :query],
49
+ # allow to set record mode from environment, see https://relishapp.com/vcr/vcr/v/3-0-3/docs/record-modes
50
+ :record => (ENV['VCR_RECORD_MODE'] && ENV['VCR_RECORD_MODE'].to_sym) || :once
51
+ }
52
+
53
+ %w(request response).each do |part|
54
+ filter_body_field(vcr_config, part, 'password')
55
+ filter_body_field(vcr_config, part, 'token')
56
+ filter_body_field(vcr_config, part, 'authorizationToken')
57
+ filter_header(vcr_config, part, 'X-Gdc-Authsst')
58
+ filter_header(vcr_config, part, 'X-Gdc-Authtt')
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end