maestrano-connector-rails 1.1.2 → 1.2.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/VERSION +1 -1
- data/app/controllers/maestrano/dependancies_controller.rb +5 -0
- data/app/controllers/maestrano/synchronizations_controller.rb +46 -0
- data/app/jobs/maestrano/connector/rails/synchronization_job.rb +49 -12
- data/app/models/maestrano/connector/rails/complex_entity.rb +1 -1
- data/app/models/maestrano/connector/rails/concerns/complex_entity.rb +4 -25
- data/app/models/maestrano/connector/rails/concerns/connec_helper.rb +17 -0
- data/app/models/maestrano/connector/rails/concerns/entity.rb +33 -34
- data/app/models/maestrano/connector/rails/concerns/entity_base.rb +34 -0
- data/app/models/maestrano/connector/rails/entity.rb +2 -2
- data/app/models/maestrano/connector/rails/entity_base.rb +5 -0
- data/config/routes.rb +7 -0
- data/lib/generators/connector/templates/entity.rb +2 -1
- data/maestrano-connector-rails.gemspec +11 -6
- data/spec/controllers/dependancies_controller_spec.rb +31 -0
- data/spec/controllers/synchronizations_controller_spec.rb +179 -0
- data/spec/dummy/app/models/entities/.keep +0 -0
- data/spec/jobs/synchronization_job_spec.rb +84 -32
- data/spec/models/complex_entity_spec.rb +11 -0
- data/spec/models/connec_helper_spec.rb +22 -0
- data/spec/models/entity_base_spec.rb +20 -0
- data/spec/models/entity_spec.rb +21 -2
- data/spec/models/external_spec.rb +9 -5
- data/spec/models/sub_entity_base_spec.rb +0 -1
- data/spec/spec_helper.rb +7 -1
- metadata +10 -5
- data/spec/dummy/app/models/entities/example_entitiy.rb +0 -26
- data/spec/dummy/app/models/maestrano/connector/rails/entity.rb +0 -3
- data/spec/dummy/app/models/maestrano/connector/rails/external.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 48d5cff94c3992312d69f4ae46493d883e9c752f
|
4
|
+
data.tar.gz: c9fb97913e6f032198ec72fc69bb2351aa220546
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9635d73732f2d8e40e545049ddf45d752b2c725d2660fc03bbbda23fc158fbab0d4445b0721736a96f4596970e9f740fd98b7f3be2efb0bc4296f3a9c68bc40b
|
7
|
+
data.tar.gz: 94486ead1d56581183097dfb52f08498bf0fe093b5b220bfe91b83803007baf6a01a0b80d5d18b71cb5be9ccb075a916681e3f396be09f5adf1494be6e5117b0
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.2.0
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class Maestrano::SynchronizationsController < Maestrano::Rails::WebHookController
|
2
|
+
def show
|
3
|
+
uid = params[:id]
|
4
|
+
organization = Maestrano::Connector::Rails::Organization.find_by_uid(uid)
|
5
|
+
return render json: { errors: {message: "Organization not found", code: 404} }, status: :not_found unless organization
|
6
|
+
|
7
|
+
h = {
|
8
|
+
group_id: organization.uid,
|
9
|
+
sync_enabled: organization.sync_enabled
|
10
|
+
}
|
11
|
+
|
12
|
+
last_sync = organization.synchronizations.last
|
13
|
+
if last_sync
|
14
|
+
h.merge!(
|
15
|
+
{
|
16
|
+
status: last_sync.status,
|
17
|
+
message: last_sync.message,
|
18
|
+
updated_at: last_sync.updated_at
|
19
|
+
}
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
render json: h
|
24
|
+
end
|
25
|
+
|
26
|
+
def create
|
27
|
+
uid = params[:group_id]
|
28
|
+
opts = params[:opts] || {}
|
29
|
+
organization = Maestrano::Connector::Rails::Organization.find_by_uid(uid)
|
30
|
+
return render json: { errors: {message: "Organization not found", code: 404} }, status: :not_found unless organization
|
31
|
+
|
32
|
+
Maestrano::Connector::Rails::SynchronizationJob.perform_later(organization, opts.with_indifferent_access)
|
33
|
+
head :created
|
34
|
+
end
|
35
|
+
|
36
|
+
def toggle_sync
|
37
|
+
uid = params[:group_id]
|
38
|
+
organization = Maestrano::Connector::Rails::Organization.find_by_uid(uid)
|
39
|
+
return render json: { errors: {message: "Organization not found", code: 404} }, status: :not_found unless organization
|
40
|
+
|
41
|
+
organization.toggle(:sync_enabled)
|
42
|
+
organization.save
|
43
|
+
|
44
|
+
render json: {sync_enabled: organization.sync_enabled}
|
45
|
+
end
|
46
|
+
end
|
@@ -35,12 +35,14 @@ module Maestrano::Connector::Rails
|
|
35
35
|
|
36
36
|
# First synchronization should be from external to Connec! only to let the smart merging works
|
37
37
|
# We do a doube sync: only from external, then only from connec!
|
38
|
+
# We also do batched sync as the first one can be quite huge
|
38
39
|
if last_synchronization.nil?
|
39
40
|
ConnectorLogger.log('info', organization, "First synchronization ever. Doing two half syncs to allow smart merging to work its magic.")
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
41
|
+
organization.synchronized_entities.select{|k, v| v}.keys.each do |entity|
|
42
|
+
ConnectorLogger.log('info', organization, "First synchronization ever. Doing half sync from external for #{entity}.")
|
43
|
+
first_sync_entity(entity.to_s, organization, connec_client, external_client, last_synchronization_date, opts, true)
|
44
|
+
ConnectorLogger.log('info', organization, "First synchronization ever. Doing half sync from Connec! for #{entity}.")
|
45
|
+
first_sync_entity(entity.to_s, organization, connec_client, external_client, last_synchronization_date, opts, false)
|
44
46
|
end
|
45
47
|
elsif opts[:only_entities]
|
46
48
|
ConnectorLogger.log('info', organization, "Synchronization is partial and will synchronize only #{opts[:only_entities].join(' ')}")
|
@@ -64,15 +66,50 @@ module Maestrano::Connector::Rails
|
|
64
66
|
end
|
65
67
|
|
66
68
|
def sync_entity(entity_name, organization, connec_client, external_client, last_synchronization_date, opts)
|
67
|
-
entity_instance =
|
69
|
+
entity_instance = instanciate_entity(entity_name, organization, connec_client, external_client, opts)
|
70
|
+
|
71
|
+
perform_sync(entity_instance, last_synchronization_date)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Does a batched sync on either external or connec!
|
75
|
+
def first_sync_entity(entity_name, organization, connec_client, external_client, last_synchronization_date, opts, external = true)
|
76
|
+
limit = Settings.first_sync_batch_size || 50
|
77
|
+
skip = 0
|
78
|
+
entities_count = limit
|
79
|
+
|
80
|
+
h = {__limit: limit}
|
81
|
+
external ? h.merge!(__skip_connec: true) : h.merge!(__skip_external: true)
|
82
|
+
entity_instance = instanciate_entity(entity_name, organization, connec_client, external_client, opts.merge(h))
|
68
83
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
84
|
+
# IF entities_count > limit
|
85
|
+
# This first sync feature is probably not implemented in the connector
|
86
|
+
# because it fetched more than the expected number of entities
|
87
|
+
# No need to fetch it a second Time
|
88
|
+
# ELSIF entities_count < limit
|
89
|
+
# No more entities to fetch
|
90
|
+
while entities_count == limit do
|
91
|
+
entity_instance.opts_merge!(__skip: skip)
|
92
|
+
entities_count = perform_sync(entity_instance, last_synchronization_date, external)
|
93
|
+
skip += limit
|
94
|
+
end
|
76
95
|
end
|
96
|
+
|
97
|
+
private
|
98
|
+
def instanciate_entity(entity_name, organization, connec_client, external_client, opts)
|
99
|
+
"Entities::#{entity_name.titleize.split.join}".constantize.new(organization, connec_client, external_client, opts.dup)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Perform the sync and return the entities_count for either external or connec
|
103
|
+
def perform_sync(entity_instance, last_synchronization_date, external = true)
|
104
|
+
entity_instance.before_sync(last_synchronization_date)
|
105
|
+
external_entities = entity_instance.get_external_entities_wrapper(last_synchronization_date)
|
106
|
+
connec_entities = entity_instance.get_connec_entities(last_synchronization_date)
|
107
|
+
mapped_entities = entity_instance.consolidate_and_map_data(connec_entities, external_entities)
|
108
|
+
entity_instance.push_entities_to_external(mapped_entities[:connec_entities])
|
109
|
+
entity_instance.push_entities_to_connec(mapped_entities[:external_entities])
|
110
|
+
entity_instance.after_sync(last_synchronization_date)
|
111
|
+
|
112
|
+
external ? entity_instance.class.count_entities(external_entities) : entity_instance.class.count_entities(connec_entities)
|
113
|
+
end
|
77
114
|
end
|
78
115
|
end
|
@@ -1,13 +1,6 @@
|
|
1
1
|
module Maestrano::Connector::Rails::Concerns::ComplexEntity
|
2
2
|
extend ActiveSupport::Concern
|
3
3
|
|
4
|
-
def initialize(organization, connec_client, external_client, opts={})
|
5
|
-
@organization = organization
|
6
|
-
@connec_client = connec_client
|
7
|
-
@external_client = external_client
|
8
|
-
@opts = opts
|
9
|
-
end
|
10
|
-
|
11
4
|
# -------------------------------------------------------------
|
12
5
|
# Complex specific methods
|
13
6
|
# Those methods needs to be implemented in each complex entity
|
@@ -20,6 +13,10 @@ module Maestrano::Connector::Rails::Concerns::ComplexEntity
|
|
20
13
|
def external_entities_names
|
21
14
|
raise "Not implemented"
|
22
15
|
end
|
16
|
+
|
17
|
+
def count_entities(entities)
|
18
|
+
entities.values.map(&:size).max
|
19
|
+
end
|
23
20
|
end
|
24
21
|
|
25
22
|
# input : {
|
@@ -141,24 +138,6 @@ module Maestrano::Connector::Rails::Concerns::ComplexEntity
|
|
141
138
|
end
|
142
139
|
end
|
143
140
|
|
144
|
-
def before_sync(last_synchronization_date)
|
145
|
-
# Does nothing by default
|
146
|
-
end
|
147
|
-
|
148
|
-
def after_sync(last_synchronization_date)
|
149
|
-
# Does nothing by default
|
150
|
-
end
|
151
|
-
|
152
|
-
# This method is called during the webhook workflow only. It should return the hash of arrays of filtered entities
|
153
|
-
# The aim is to have the same filtering as with the Connec! filters on API calls in the webhooks
|
154
|
-
# input : {
|
155
|
-
# external_entities_names[0]: [unmapped_external_entity1}, unmapped_external_entity2],
|
156
|
-
# external_entities_names[1]: [unmapped_external_entity3}, unmapped_external_entity4]
|
157
|
-
# }
|
158
|
-
def filter_connec_entities(entities)
|
159
|
-
entities
|
160
|
-
end
|
161
|
-
|
162
141
|
def instantiate_sub_entity_instance(entity_name)
|
163
142
|
"Entities::SubEntities::#{entity_name.titleize.split.join}".constantize.new(@organization, @connec_client, @external_client, @opts)
|
164
143
|
end
|
@@ -2,12 +2,29 @@ module Maestrano::Connector::Rails::Concerns::ConnecHelper
|
|
2
2
|
extend ActiveSupport::Concern
|
3
3
|
|
4
4
|
module ClassMethods
|
5
|
+
def dependancies
|
6
|
+
# Meant to be overloaded if needed
|
7
|
+
{
|
8
|
+
connec: '1.0',
|
9
|
+
impac: '1.0',
|
10
|
+
maestrano_hub: '1.0'
|
11
|
+
}
|
12
|
+
end
|
5
13
|
|
6
14
|
def get_client(organization)
|
7
15
|
client = Maestrano::Connec::Client[organization.tenant].new(organization.uid)
|
8
16
|
client.class.headers('CONNEC-EXTERNAL-IDS' => 'true')
|
9
17
|
client
|
10
18
|
end
|
19
|
+
|
20
|
+
def connec_version(organization)
|
21
|
+
@@connec_version = Rails.cache.fetch('connec_version', namespace: 'maestrano', expires_in: 1.day) do
|
22
|
+
response = get_client(organization).class.get("#{Maestrano[organization.tenant].param('connec.host')}/version")
|
23
|
+
response = JSON.parse(response.body)
|
24
|
+
@@connec_version = response['ci_branch']
|
25
|
+
end
|
26
|
+
@@connec_version
|
27
|
+
end
|
11
28
|
|
12
29
|
# Replace the ids arrays by the external id
|
13
30
|
# If a reference has no id for this oauth_provider and oauth_uid but has one for connec returns nil
|
@@ -1,13 +1,6 @@
|
|
1
1
|
module Maestrano::Connector::Rails::Concerns::Entity
|
2
2
|
extend ActiveSupport::Concern
|
3
3
|
|
4
|
-
def initialize(organization, connec_client, external_client, opts={})
|
5
|
-
@organization = organization
|
6
|
-
@connec_client = connec_client
|
7
|
-
@external_client = external_client
|
8
|
-
@opts = opts
|
9
|
-
end
|
10
|
-
|
11
4
|
module ClassMethods
|
12
5
|
# ----------------------------------------------
|
13
6
|
# IdMap methods
|
@@ -131,8 +124,21 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
131
124
|
def can_update_external?
|
132
125
|
true
|
133
126
|
end
|
127
|
+
|
128
|
+
# ----------------------------------------------
|
129
|
+
# Helper methods
|
130
|
+
# ----------------------------------------------
|
131
|
+
def count_entities(entities)
|
132
|
+
entities.size
|
133
|
+
end
|
134
134
|
end
|
135
135
|
|
136
|
+
# ==============================================
|
137
|
+
# ==============================================
|
138
|
+
# Instance methods
|
139
|
+
# ==============================================
|
140
|
+
# ==============================================
|
141
|
+
|
136
142
|
# ----------------------------------------------
|
137
143
|
# Mapper methods
|
138
144
|
# ----------------------------------------------
|
@@ -159,7 +165,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
159
165
|
# * $filter (see Connec! documentation)
|
160
166
|
# * $orderby (see Connec! documentation)
|
161
167
|
def get_connec_entities(last_synchronization_date=nil)
|
162
|
-
return [] if @opts[:
|
168
|
+
return [] if @opts[:__skip_connec] || !self.class.can_read_connec?
|
163
169
|
|
164
170
|
Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Fetching Connec! #{self.class.connec_entity_name}")
|
165
171
|
|
@@ -169,6 +175,13 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
169
175
|
|
170
176
|
# Fetch first page
|
171
177
|
page_number = 0
|
178
|
+
|
179
|
+
batched_fetch = @opts[:__limit] && @opts[:__skip]
|
180
|
+
if batched_fetch
|
181
|
+
query_params[:$top] = @opts[:__limit]
|
182
|
+
query_params[:$skip] = @opts[:__skip]
|
183
|
+
end
|
184
|
+
|
172
185
|
if last_synchronization_date.blank? || @opts[:full_sync]
|
173
186
|
query_params[:$filter] = @opts[:$filter] if @opts[:$filter]
|
174
187
|
else
|
@@ -181,14 +194,17 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
181
194
|
entities = response_hash["#{self.class.normalized_connec_entity_name}"]
|
182
195
|
entities = [entities] if self.class.singleton?
|
183
196
|
|
184
|
-
#
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
197
|
+
# Only the first page if batched_fetch
|
198
|
+
unless batched_fetch
|
199
|
+
# Fetch subsequent pages
|
200
|
+
while response_hash['pagination'] && response_hash['pagination']['next']
|
201
|
+
page_number += 1
|
202
|
+
# ugly way to convert https://api-connec/api/v2/group_id/organizations?next_page_params to /organizations?next_page_params
|
203
|
+
next_page = response_hash['pagination']['next'].gsub(/^(.*)\/#{self.class.normalized_connec_entity_name}/, self.class.normalized_connec_entity_name)
|
189
204
|
|
190
|
-
|
191
|
-
|
205
|
+
response_hash = fetch_connec(next_page, page_number)
|
206
|
+
entities << response_hash["#{self.class.normalized_connec_entity_name}"]
|
207
|
+
end
|
192
208
|
end
|
193
209
|
|
194
210
|
entities.flatten!
|
@@ -224,7 +240,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
224
240
|
# External methods
|
225
241
|
# ----------------------------------------------
|
226
242
|
def get_external_entities_wrapper(last_synchronization_date=nil)
|
227
|
-
return [] if @opts[:
|
243
|
+
return [] if @opts[:__skip_external] || !self.class.can_read_external?
|
228
244
|
get_external_entities(last_synchronization_date)
|
229
245
|
end
|
230
246
|
|
@@ -299,12 +315,6 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
299
315
|
raise "Not implemented"
|
300
316
|
end
|
301
317
|
|
302
|
-
# This method is called during the webhook workflow only. It should return the array of filtered entities
|
303
|
-
# The aim is to have the same filtering as with the Connec! filters on API calls in the webhooks
|
304
|
-
def filter_connec_entities(entities)
|
305
|
-
entities
|
306
|
-
end
|
307
|
-
|
308
318
|
# ----------------------------------------------
|
309
319
|
# General methods
|
310
320
|
# ----------------------------------------------
|
@@ -313,6 +323,7 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
313
323
|
# * Maps not discarded entities and associates them with their idmap, or create one if there isn't any
|
314
324
|
# * Returns a hash {connec_entities: [], external_entities: []}
|
315
325
|
def consolidate_and_map_data(connec_entities, external_entities)
|
326
|
+
Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Consolidating and mapping #{self.class.external_entity_name}/#{self.class.connec_entity_name}")
|
316
327
|
return consolidate_and_map_singleton(connec_entities, external_entities) if self.class.singleton?
|
317
328
|
|
318
329
|
mapped_connec_entities = consolidate_and_map_connec_entities(connec_entities, external_entities, self.class.references, self.class.external_entity_name)
|
@@ -395,18 +406,6 @@ module Maestrano::Connector::Rails::Concerns::Entity
|
|
395
406
|
end
|
396
407
|
end
|
397
408
|
|
398
|
-
# ----------------------------------------------
|
399
|
-
# After and before sync
|
400
|
-
# ----------------------------------------------
|
401
|
-
def before_sync(last_synchronization_date)
|
402
|
-
# Does nothing by default
|
403
|
-
end
|
404
|
-
|
405
|
-
def after_sync(last_synchronization_date)
|
406
|
-
# Does nothing by default
|
407
|
-
end
|
408
|
-
|
409
|
-
|
410
409
|
# ----------------------------------------------
|
411
410
|
# Internal helper methods
|
412
411
|
# ----------------------------------------------
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Maestrano::Connector::Rails::Concerns::EntityBase
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
def initialize(organization, connec_client, external_client, opts={})
|
5
|
+
@organization = organization
|
6
|
+
@connec_client = connec_client
|
7
|
+
@external_client = external_client
|
8
|
+
@opts = opts
|
9
|
+
end
|
10
|
+
|
11
|
+
def opts_merge!(opts)
|
12
|
+
@opts.merge!(opts)
|
13
|
+
end
|
14
|
+
|
15
|
+
def before_sync(last_synchronization_date)
|
16
|
+
# Does nothing by default
|
17
|
+
end
|
18
|
+
|
19
|
+
def after_sync(last_synchronization_date)
|
20
|
+
# Does nothing by default
|
21
|
+
end
|
22
|
+
|
23
|
+
# This method is called during the webhook workflow only. It should return the hash of arrays of filtered entities
|
24
|
+
# The aim is to have the same filtering as with the Connec! filters on API calls in the webhooks
|
25
|
+
# input :
|
26
|
+
# For non complex entities [unmapped_external_entity1, unmapped_external_entity2]
|
27
|
+
# For complex entities {
|
28
|
+
# external_entities_names[0]: [unmapped_external_entity1, unmapped_external_entity2],
|
29
|
+
# external_entities_names[1]: [unmapped_external_entity3, unmapped_external_entity4]
|
30
|
+
# }
|
31
|
+
def filter_connec_entities(entities)
|
32
|
+
entities
|
33
|
+
end
|
34
|
+
end
|
data/config/routes.rb
CHANGED
@@ -4,5 +4,12 @@ Maestrano::Connector::Rails::Engine.routes.draw do
|
|
4
4
|
namespace :maestrano do
|
5
5
|
match 'signout', to: 'sessions#destroy', as: 'signout', via: [:get, :post]
|
6
6
|
post 'connec/notifications/:tenant' => 'connec#notifications'
|
7
|
+
|
8
|
+
resources :synchronizations, only: [:show, :create] do
|
9
|
+
collection do
|
10
|
+
put :toggle_sync
|
11
|
+
end
|
12
|
+
end
|
13
|
+
resources :dependancies, only: [:index]
|
7
14
|
end
|
8
15
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class Maestrano::Connector::Rails::Entity
|
1
|
+
class Maestrano::Connector::Rails::Entity < Maestrano::Connector::Rails::EntityBase
|
2
2
|
include Maestrano::Connector::Rails::Concerns::Entity
|
3
3
|
|
4
4
|
# In this class and in all entities which inherit from it, the following instance variables are available:
|
@@ -13,6 +13,7 @@ class Maestrano::Connector::Rails::Entity
|
|
13
13
|
# TODO
|
14
14
|
# This method should return only entities that have been updated since the last_synchronization_date
|
15
15
|
# It should also implements an option to do a full synchronization when @opts[:full_sync] == true or when there is no last_synchronization_date
|
16
|
+
# It should also support [:__limit] and [:__skip] opts, meaning that if they are present, it should return only @[:__limit] entities while skipping the @opts[:__skip] firsts
|
16
17
|
# Maestrano::Connector::Rails::ConnectorLogger.log('info', @organization, "Received data: Source=#{Maestrano::Connector::Rails::External.external_name}, Entity=#{self.class.external_entity_name}, Response=#{entities}")
|
17
18
|
end
|
18
19
|
|
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: maestrano-connector-rails 1.
|
5
|
+
# stub: maestrano-connector-rails 1.2.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "maestrano-connector-rails"
|
9
|
-
s.version = "1.
|
9
|
+
s.version = "1.2.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
13
13
|
s.authors = ["Pierre Berard"]
|
14
|
-
s.date = "2016-
|
14
|
+
s.date = "2016-07-01"
|
15
15
|
s.description = "Maestrano is the next generation marketplace for SME applications. See https://maestrano.com for details."
|
16
16
|
s.email = "pierre.berard@maestrano.com"
|
17
17
|
s.executables = ["rails"]
|
@@ -32,7 +32,9 @@ Gem::Specification.new do |s|
|
|
32
32
|
"app/controllers/maestrano/application_controller.rb",
|
33
33
|
"app/controllers/maestrano/auth/saml_controller.rb",
|
34
34
|
"app/controllers/maestrano/connec_controller.rb",
|
35
|
+
"app/controllers/maestrano/dependancies_controller.rb",
|
35
36
|
"app/controllers/maestrano/sessions_controller.rb",
|
37
|
+
"app/controllers/maestrano/synchronizations_controller.rb",
|
36
38
|
"app/helpers/maestrano/connector/rails/session_helper.rb",
|
37
39
|
"app/jobs/maestrano/connector/rails/all_synchronizations_job.rb",
|
38
40
|
"app/jobs/maestrano/connector/rails/push_to_connec_job.rb",
|
@@ -42,11 +44,13 @@ Gem::Specification.new do |s|
|
|
42
44
|
"app/models/maestrano/connector/rails/concerns/connec_helper.rb",
|
43
45
|
"app/models/maestrano/connector/rails/concerns/connector_logger.rb",
|
44
46
|
"app/models/maestrano/connector/rails/concerns/entity.rb",
|
47
|
+
"app/models/maestrano/connector/rails/concerns/entity_base.rb",
|
45
48
|
"app/models/maestrano/connector/rails/concerns/external.rb",
|
46
49
|
"app/models/maestrano/connector/rails/concerns/sub_entity_base.rb",
|
47
50
|
"app/models/maestrano/connector/rails/connec_helper.rb",
|
48
51
|
"app/models/maestrano/connector/rails/connector_logger.rb",
|
49
52
|
"app/models/maestrano/connector/rails/entity.rb",
|
53
|
+
"app/models/maestrano/connector/rails/entity_base.rb",
|
50
54
|
"app/models/maestrano/connector/rails/external.rb",
|
51
55
|
"app/models/maestrano/connector/rails/id_map.rb",
|
52
56
|
"app/models/maestrano/connector/rails/organization.rb",
|
@@ -102,8 +106,10 @@ Gem::Specification.new do |s|
|
|
102
106
|
"maestrano.png",
|
103
107
|
"release_notes.md",
|
104
108
|
"spec/controllers/connec_controller_spec.rb",
|
109
|
+
"spec/controllers/dependancies_controller_spec.rb",
|
105
110
|
"spec/controllers/group_users_controller_spec.rb",
|
106
111
|
"spec/controllers/groups_controller_spec.rb",
|
112
|
+
"spec/controllers/synchronizations_controller_spec.rb",
|
107
113
|
"spec/dummy/README.md",
|
108
114
|
"spec/dummy/Rakefile",
|
109
115
|
"spec/dummy/app/assets/images/.keep",
|
@@ -118,9 +124,7 @@ Gem::Specification.new do |s|
|
|
118
124
|
"spec/dummy/app/mailers/.keep",
|
119
125
|
"spec/dummy/app/models/.keep",
|
120
126
|
"spec/dummy/app/models/concerns/.keep",
|
121
|
-
"spec/dummy/app/models/entities
|
122
|
-
"spec/dummy/app/models/maestrano/connector/rails/entity.rb",
|
123
|
-
"spec/dummy/app/models/maestrano/connector/rails/external.rb",
|
127
|
+
"spec/dummy/app/models/entities/.keep",
|
124
128
|
"spec/dummy/app/views/home/index.html.erb",
|
125
129
|
"spec/dummy/app/views/layouts/application.html.erb",
|
126
130
|
"spec/dummy/bin/bundle",
|
@@ -170,6 +174,7 @@ Gem::Specification.new do |s|
|
|
170
174
|
"spec/models/complex_entity_spec.rb",
|
171
175
|
"spec/models/connec_helper_spec.rb",
|
172
176
|
"spec/models/connector_logger_spec.rb",
|
177
|
+
"spec/models/entity_base_spec.rb",
|
173
178
|
"spec/models/entity_spec.rb",
|
174
179
|
"spec/models/external_spec.rb",
|
175
180
|
"spec/models/id_map_spec.rb",
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Maestrano::DependanciesController, type: :controller do
|
4
|
+
routes { Maestrano::Connector::Rails::Engine.routes }
|
5
|
+
|
6
|
+
describe 'index' do
|
7
|
+
subject { get :index }
|
8
|
+
|
9
|
+
context 'without authentication' do
|
10
|
+
before {
|
11
|
+
controller.class.before_filter :authenticate_maestrano!
|
12
|
+
}
|
13
|
+
|
14
|
+
it 'respond with unauthorized' do
|
15
|
+
subject
|
16
|
+
expect(response.status).to eq(401)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'with authentication' do
|
21
|
+
before {
|
22
|
+
controller.class.skip_before_filter :authenticate_maestrano!
|
23
|
+
}
|
24
|
+
|
25
|
+
it 'renders the dependancies hash' do
|
26
|
+
subject
|
27
|
+
expect(response.body).to eql(Maestrano::Connector::Rails::ConnecHelper.dependancies.to_json)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Maestrano::SynchronizationsController, type: :controller do
|
4
|
+
routes { Maestrano::Connector::Rails::Engine.routes }
|
5
|
+
|
6
|
+
let(:uid) { 'cld-aaaa' }
|
7
|
+
|
8
|
+
describe 'show' do
|
9
|
+
subject { get :show, id: uid }
|
10
|
+
|
11
|
+
|
12
|
+
context 'without authentication' do
|
13
|
+
before {
|
14
|
+
controller.class.before_filter :authenticate_maestrano!
|
15
|
+
}
|
16
|
+
|
17
|
+
it 'respond with unauthorized' do
|
18
|
+
subject
|
19
|
+
expect(response.status).to eq(401)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'with authentication' do
|
24
|
+
before {
|
25
|
+
controller.class.skip_before_filter :authenticate_maestrano!
|
26
|
+
}
|
27
|
+
|
28
|
+
context 'when organization is not found' do
|
29
|
+
let!(:organization) { create(:organization, uid: 'cld-bbbb') }
|
30
|
+
|
31
|
+
it 'is a 404' do
|
32
|
+
subject
|
33
|
+
expect(response.status).to eq(404)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'when organization is found' do
|
38
|
+
let!(:organization) { create(:organization, uid: uid) }
|
39
|
+
|
40
|
+
it 'is a success' do
|
41
|
+
subject
|
42
|
+
expect(response.status).to eq(200)
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'with no last sync' do
|
46
|
+
it 'renders a partial json' do
|
47
|
+
subject
|
48
|
+
expect(JSON.parse(response.body)).to eql(
|
49
|
+
JSON.parse({
|
50
|
+
group_id: organization.uid,
|
51
|
+
sync_enabled: organization.sync_enabled,
|
52
|
+
}.to_json)
|
53
|
+
)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'with a last sync' do
|
58
|
+
let!(:sync1) { create(:synchronization, organization: organization) }
|
59
|
+
let!(:sync2) { create(:synchronization, organization: organization, message: 'msg') }
|
60
|
+
|
61
|
+
it 'renders a full json' do
|
62
|
+
subject
|
63
|
+
expect(JSON.parse(response.body)).to eql(
|
64
|
+
JSON.parse({
|
65
|
+
group_id: organization.uid,
|
66
|
+
sync_enabled: organization.sync_enabled,
|
67
|
+
status: sync2.status,
|
68
|
+
message: sync2.message,
|
69
|
+
updated_at: sync2.updated_at
|
70
|
+
}.to_json)
|
71
|
+
)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe 'create' do
|
79
|
+
let(:opts) { {'only_entities' => ['customer']} }
|
80
|
+
subject { post :create, group_id: uid, opts: opts }
|
81
|
+
|
82
|
+
|
83
|
+
context 'without authentication' do
|
84
|
+
before {
|
85
|
+
controller.class.before_filter :authenticate_maestrano!
|
86
|
+
}
|
87
|
+
|
88
|
+
it 'respond with unauthorized' do
|
89
|
+
subject
|
90
|
+
expect(response.status).to eq(401)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'with authentication' do
|
95
|
+
before {
|
96
|
+
controller.class.skip_before_filter :authenticate_maestrano!
|
97
|
+
}
|
98
|
+
|
99
|
+
context 'when organization is not found' do
|
100
|
+
let!(:organization) { create(:organization, uid: 'cld-bbbb') }
|
101
|
+
|
102
|
+
it 'is a 404' do
|
103
|
+
subject
|
104
|
+
expect(response.status).to eq(404)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'when organization is found' do
|
109
|
+
let!(:organization) { create(:organization, uid: uid) }
|
110
|
+
|
111
|
+
it 'is a success' do
|
112
|
+
subject
|
113
|
+
expect(response.status).to eq(201)
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'queues a sync' do
|
117
|
+
expect(Maestrano::Connector::Rails::SynchronizationJob).to receive(:perform_later).with(organization, opts)
|
118
|
+
subject
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe 'toggle_sync' do
|
125
|
+
subject { put :toggle_sync, group_id: uid }
|
126
|
+
|
127
|
+
|
128
|
+
context 'without authentication' do
|
129
|
+
before {
|
130
|
+
controller.class.before_filter :authenticate_maestrano!
|
131
|
+
}
|
132
|
+
|
133
|
+
it 'respond with unauthorized' do
|
134
|
+
subject
|
135
|
+
expect(response.status).to eq(401)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'with authentication' do
|
140
|
+
before {
|
141
|
+
controller.class.skip_before_filter :authenticate_maestrano!
|
142
|
+
}
|
143
|
+
|
144
|
+
context 'when organization is not found' do
|
145
|
+
let!(:organization) { create(:organization, uid: 'cld-bbbb') }
|
146
|
+
|
147
|
+
it 'is a 404' do
|
148
|
+
subject
|
149
|
+
expect(response.status).to eq(404)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context 'when organization is found' do
|
154
|
+
let!(:organization) { create(:organization, uid: uid) }
|
155
|
+
|
156
|
+
it 'is a success' do
|
157
|
+
subject
|
158
|
+
expect(response.status).to eq(200)
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'when sync_enabled is true' do
|
162
|
+
before { organization.update(sync_enabled: true) }
|
163
|
+
it 'disables the organizatio syncs' do
|
164
|
+
subject
|
165
|
+
expect(organization.reload.sync_enabled).to be false
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
context 'when sync_enabled is false' do
|
170
|
+
before { organization.update(sync_enabled: false) }
|
171
|
+
it 'enables the organizatio syncs' do
|
172
|
+
subject
|
173
|
+
expect(organization.reload.sync_enabled).to be true
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
File without changes
|
@@ -20,7 +20,7 @@ describe Maestrano::Connector::Rails::SynchronizationJob do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
context 'with sync_enabled set to true' do
|
23
|
-
before {organization.update(sync_enabled: true)}
|
23
|
+
before { organization.update(sync_enabled: true)}
|
24
24
|
|
25
25
|
context 'with a sync still running for less than 30 minutes' do
|
26
26
|
let!(:running_sync) { create(:synchronization, organization: organization, status: 'RUNNING', created_at: 29.minutes.ago) }
|
@@ -67,17 +67,18 @@ describe Maestrano::Connector::Rails::SynchronizationJob do
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
-
it { performes }
|
71
70
|
|
72
71
|
context 'first sync' do
|
73
72
|
it 'does two half syncs' do
|
74
|
-
expect_any_instance_of(Maestrano::Connector::Rails::SynchronizationJob).to receive(:
|
73
|
+
expect_any_instance_of(Maestrano::Connector::Rails::SynchronizationJob).to receive(:first_sync_entity).exactly(2 * organization.synchronized_entities.count).times
|
75
74
|
subject
|
76
75
|
end
|
77
76
|
end
|
78
77
|
|
79
78
|
context 'subsequent sync' do
|
80
79
|
let!(:old_sync) { create(:synchronization, partial: false, status: 'SUCCESS', organization: organization) }
|
80
|
+
|
81
|
+
it { performes }
|
81
82
|
|
82
83
|
it 'calls sync entity on all the organization synchronized entities set to true' do
|
83
84
|
organization.synchronized_entities[organization.synchronized_entities.keys.first] = false
|
@@ -107,42 +108,93 @@ describe Maestrano::Connector::Rails::SynchronizationJob do
|
|
107
108
|
end
|
108
109
|
end
|
109
110
|
|
110
|
-
describe '
|
111
|
+
describe 'other methods' do
|
111
112
|
subject { Maestrano::Connector::Rails::SynchronizationJob.new }
|
112
113
|
|
113
|
-
|
114
|
-
|
115
|
-
|
114
|
+
describe 'sync_entity' do
|
115
|
+
|
116
|
+
context 'non complex entity' do
|
117
|
+
before {
|
118
|
+
class Entities::Person < Maestrano::Connector::Rails::Entity
|
119
|
+
end
|
120
|
+
}
|
121
|
+
|
122
|
+
it 'calls the seven methods' do
|
123
|
+
expect_any_instance_of(Entities::Person).to receive(:before_sync)
|
124
|
+
expect_any_instance_of(Entities::Person).to receive(:get_connec_entities).and_return([])
|
125
|
+
expect_any_instance_of(Entities::Person).to receive(:get_external_entities_wrapper).and_return([])
|
126
|
+
expect_any_instance_of(Entities::Person).to receive(:consolidate_and_map_data).and_return({})
|
127
|
+
expect_any_instance_of(Entities::Person).to receive(:push_entities_to_external)
|
128
|
+
expect_any_instance_of(Entities::Person).to receive(:push_entities_to_connec)
|
129
|
+
expect_any_instance_of(Entities::Person).to receive(:after_sync)
|
130
|
+
subject.sync_entity('person', organization, nil, nil, nil, {})
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context 'complex entity' do
|
135
|
+
before {
|
136
|
+
class Entities::SomeStuff < Maestrano::Connector::Rails::ComplexEntity
|
137
|
+
end
|
138
|
+
}
|
139
|
+
|
140
|
+
it 'calls the seven methods' do
|
141
|
+
expect_any_instance_of(Entities::SomeStuff).to receive(:before_sync)
|
142
|
+
expect_any_instance_of(Entities::SomeStuff).to receive(:get_connec_entities).and_return({})
|
143
|
+
expect_any_instance_of(Entities::SomeStuff).to receive(:get_external_entities_wrapper).and_return({})
|
144
|
+
expect_any_instance_of(Entities::SomeStuff).to receive(:consolidate_and_map_data).and_return({})
|
145
|
+
expect_any_instance_of(Entities::SomeStuff).to receive(:push_entities_to_external)
|
146
|
+
expect_any_instance_of(Entities::SomeStuff).to receive(:push_entities_to_connec)
|
147
|
+
expect_any_instance_of(Entities::SomeStuff).to receive(:after_sync)
|
148
|
+
subject.sync_entity('some stuff', organization, nil, nil, nil, {})
|
116
149
|
end
|
117
|
-
}
|
118
|
-
|
119
|
-
it 'calls the seven methods' do
|
120
|
-
expect_any_instance_of(Entities::Person).to receive(:before_sync)
|
121
|
-
expect_any_instance_of(Entities::Person).to receive(:get_connec_entities)
|
122
|
-
expect_any_instance_of(Entities::Person).to receive(:get_external_entities_wrapper)
|
123
|
-
expect_any_instance_of(Entities::Person).to receive(:consolidate_and_map_data).and_return({})
|
124
|
-
expect_any_instance_of(Entities::Person).to receive(:push_entities_to_external)
|
125
|
-
expect_any_instance_of(Entities::Person).to receive(:push_entities_to_connec)
|
126
|
-
expect_any_instance_of(Entities::Person).to receive(:after_sync)
|
127
|
-
subject.sync_entity('person', organization, nil, nil, nil, {})
|
128
150
|
end
|
129
151
|
end
|
130
152
|
|
131
|
-
|
132
|
-
|
133
|
-
|
153
|
+
describe 'first_sync_entity' do
|
154
|
+
let(:batch_limit) { 50 }
|
155
|
+
|
156
|
+
context 'non complex entity' do
|
157
|
+
before {
|
158
|
+
class Entities::Person < Maestrano::Connector::Rails::Entity
|
159
|
+
end
|
160
|
+
allow_any_instance_of(Entities::Person).to receive(:get_connec_entities).and_return([])
|
161
|
+
allow_any_instance_of(Entities::Person).to receive(:get_external_entities_wrapper).and_return([])
|
162
|
+
allow_any_instance_of(Entities::Person).to receive(:consolidate_and_map_data).and_return({})
|
163
|
+
allow_any_instance_of(Entities::Person).to receive(:push_entities_to_external)
|
164
|
+
allow_any_instance_of(Entities::Person).to receive(:push_entities_to_connec)
|
165
|
+
}
|
166
|
+
|
167
|
+
context 'with pagination' do
|
168
|
+
context 'with more than 50 entities' do
|
169
|
+
it 'calls perform_sync several time' do
|
170
|
+
allow(subject).to receive(:perform_sync).and_return(batch_limit, 0)
|
171
|
+
expect_any_instance_of(Entities::Person).to receive(:opts_merge!).twice
|
172
|
+
expect(subject).to receive(:perform_sync).twice
|
173
|
+
|
174
|
+
subject.first_sync_entity('person', organization, nil, nil, nil, {}, true)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'with less than 50 entities' do
|
179
|
+
it 'calls perform_sync once' do
|
180
|
+
allow(subject).to receive(:perform_sync).and_return(batch_limit - 10)
|
181
|
+
expect_any_instance_of(Entities::Person).to receive(:opts_merge!).once.with({__skip: 0})
|
182
|
+
expect(subject).to receive(:perform_sync).once
|
183
|
+
|
184
|
+
subject.first_sync_entity('person', organization, nil, nil, nil, {}, true)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
context 'without pagination' do
|
190
|
+
it 'calls perform_sync once' do
|
191
|
+
allow(subject).to receive(:perform_sync).and_return(batch_limit + 10)
|
192
|
+
expect_any_instance_of(Entities::Person).to receive(:opts_merge!).once.with({__skip: 0})
|
193
|
+
expect(subject).to receive(:perform_sync).once
|
194
|
+
|
195
|
+
subject.first_sync_entity('person', organization, nil, nil, nil, {}, true)
|
196
|
+
end
|
134
197
|
end
|
135
|
-
}
|
136
|
-
|
137
|
-
it 'calls the seven methods' do
|
138
|
-
expect_any_instance_of(Entities::SomeStuff).to receive(:before_sync)
|
139
|
-
expect_any_instance_of(Entities::SomeStuff).to receive(:get_connec_entities)
|
140
|
-
expect_any_instance_of(Entities::SomeStuff).to receive(:get_external_entities_wrapper)
|
141
|
-
expect_any_instance_of(Entities::SomeStuff).to receive(:consolidate_and_map_data).and_return({})
|
142
|
-
expect_any_instance_of(Entities::SomeStuff).to receive(:push_entities_to_external)
|
143
|
-
expect_any_instance_of(Entities::SomeStuff).to receive(:push_entities_to_connec)
|
144
|
-
expect_any_instance_of(Entities::SomeStuff).to receive(:after_sync)
|
145
|
-
subject.sync_entity('some stuff', organization, nil, nil, nil, {})
|
146
198
|
end
|
147
199
|
end
|
148
200
|
end
|
@@ -11,6 +11,17 @@ describe Maestrano::Connector::Rails::ComplexEntity do
|
|
11
11
|
describe 'external_entities_names' do
|
12
12
|
it { expect{ subject.external_entities_names }.to raise_error('Not implemented') }
|
13
13
|
end
|
14
|
+
|
15
|
+
describe 'count_entities' do
|
16
|
+
it 'returns the biggest array size' do
|
17
|
+
entities = {
|
18
|
+
'people' => [*1..27],
|
19
|
+
'organizations' => [*1..39],
|
20
|
+
'items' => []
|
21
|
+
}
|
22
|
+
expect(subject.count_entities(entities)).to eql(39)
|
23
|
+
end
|
24
|
+
end
|
14
25
|
end
|
15
26
|
|
16
27
|
describe 'instance methods' do
|
@@ -5,6 +5,28 @@ describe Maestrano::Connector::Rails::ConnecHelper do
|
|
5
5
|
|
6
6
|
let!(:organization) { create(:organization) }
|
7
7
|
|
8
|
+
describe 'dependancies' do
|
9
|
+
it 'returns a default hash' do
|
10
|
+
expect(subject.dependancies).to eql({
|
11
|
+
connec: '1.0',
|
12
|
+
impac: '1.0',
|
13
|
+
maestrano_hub: '1.0'
|
14
|
+
})
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'connec_version' do
|
19
|
+
let!(:organization) { create(:organization, tenant: 'default') }
|
20
|
+
before {
|
21
|
+
allow(Maestrano::Connec::Client[organization.tenant]).to receive(:get).and_return(ActionDispatch::Response.new(200, {}, {ci_build_number: '111', ci_branch: '1.1', ci_commit: '111'}.to_json, {}))
|
22
|
+
}
|
23
|
+
|
24
|
+
it 'returns the connec_version' do
|
25
|
+
expect(subject.connec_version(organization)).to eql('1.1')
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
8
30
|
describe 'unfold_references' do
|
9
31
|
let(:connec_hash) {
|
10
32
|
{
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Maestrano::Connector::Rails::EntityBase do
|
4
|
+
describe 'instance methods' do
|
5
|
+
let!(:organization) { create(:organization, uid: 'cld-123') }
|
6
|
+
let!(:connec_client) { Maestrano::Connec::Client[organization.tenant].new(organization.uid) }
|
7
|
+
let!(:external_client) { Object.new }
|
8
|
+
let(:opts) { {} }
|
9
|
+
subject { Maestrano::Connector::Rails::EntityBase.new(organization, connec_client, external_client, opts) }
|
10
|
+
|
11
|
+
describe 'opts_merge!' do
|
12
|
+
let(:opts) { {a: 1, opts: 2} }
|
13
|
+
|
14
|
+
it 'merges options with the instance variable' do
|
15
|
+
subject.opts_merge!(opts: 3, test: 'test')
|
16
|
+
expect(subject.instance_variable_get(:@opts)).to eql(a: 1, opts: 3, test: 'test')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/spec/models/entity_spec.rb
CHANGED
@@ -110,6 +110,12 @@ describe Maestrano::Connector::Rails::Entity do
|
|
110
110
|
describe 'connec_matching_fields' do
|
111
111
|
it { expect(subject.connec_matching_fields).to be_nil }
|
112
112
|
end
|
113
|
+
|
114
|
+
describe 'count_entities' do
|
115
|
+
it 'returns the array size' do
|
116
|
+
expect(subject.count_entities([*1..27])).to eql(27)
|
117
|
+
end
|
118
|
+
end
|
113
119
|
end
|
114
120
|
|
115
121
|
describe 'instance methods' do
|
@@ -189,7 +195,7 @@ describe Maestrano::Connector::Rails::Entity do
|
|
189
195
|
end
|
190
196
|
|
191
197
|
describe 'when skip_connec' do
|
192
|
-
let(:opts) { {
|
198
|
+
let(:opts) { {__skip_connec: true} }
|
193
199
|
it { expect(subject.get_connec_entities(nil)).to eql([]) }
|
194
200
|
end
|
195
201
|
|
@@ -211,6 +217,19 @@ describe Maestrano::Connector::Rails::Entity do
|
|
211
217
|
allow(connec_client).to receive(:get).and_return(ActionDispatch::Response.new(200, {}, {people: []}.to_json, {}))
|
212
218
|
}
|
213
219
|
|
220
|
+
context 'with limit and skip opts' do
|
221
|
+
let(:opts) { {__skip: 100, __limit: 50} }
|
222
|
+
before {
|
223
|
+
allow(connec_client).to receive(:get).and_return(ActionDispatch::Response.new(200, {}, {people: [], pagination: {next: "https://api-connec.maestrano.com/api/v2/cld-dkg601/people?%24skip=10&%24top=10"}}.to_json, {}), ActionDispatch::Response.new(200, {}, {people: []}.to_json, {}))
|
224
|
+
}
|
225
|
+
|
226
|
+
it 'performs a size limited date and do not paginate' do
|
227
|
+
uri_param = {"$filter" => "updated_at gt '#{sync.updated_at.iso8601}'", "$skip" => 100, "$top" => 50}.to_query
|
228
|
+
expect(connec_client).to receive(:get).once.with("#{connec_name.downcase.pluralize}?#{uri_param}")
|
229
|
+
subject.get_connec_entities(sync.updated_at)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
214
233
|
context 'when opts[:full_sync] is true' do
|
215
234
|
let(:opts) { {full_sync: true} }
|
216
235
|
it 'performs a full get' do
|
@@ -474,7 +493,7 @@ describe Maestrano::Connector::Rails::Entity do
|
|
474
493
|
end
|
475
494
|
|
476
495
|
context 'when skip external' do
|
477
|
-
let(:opts) { {
|
496
|
+
let(:opts) { {__skip_external: true} }
|
478
497
|
|
479
498
|
it 'returns an empty array and does not call get_external_entities' do
|
480
499
|
expect(subject).to_not receive(:get_connec_entities)
|
@@ -3,17 +3,21 @@ require 'spec_helper'
|
|
3
3
|
describe Maestrano::Connector::Rails::External do
|
4
4
|
subject { Maestrano::Connector::Rails::External }
|
5
5
|
|
6
|
+
before {
|
7
|
+
allow(Maestrano::Connector::Rails::External).to receive(:external_name).and_call_original
|
8
|
+
allow(Maestrano::Connector::Rails::External).to receive(:get_client).and_call_original
|
9
|
+
allow(Maestrano::Connector::Rails::External).to receive(:entities_list).and_call_original
|
10
|
+
}
|
11
|
+
|
6
12
|
describe 'external_name' do
|
7
|
-
it { expect
|
13
|
+
it { expect{ subject.external_name }.to raise_error(RuntimeError) }
|
8
14
|
end
|
9
15
|
|
10
16
|
describe 'get_client' do
|
11
|
-
|
12
|
-
|
13
|
-
it { expect(subject.get_client(organization)).to eql(nil) }
|
17
|
+
it { expect{ subject.get_client(nil) }.to raise_error(RuntimeError) }
|
14
18
|
end
|
15
19
|
|
16
20
|
describe 'entities_list' do
|
17
|
-
it { expect
|
21
|
+
it { expect{ subject.entities_list }.to raise_error(RuntimeError) }
|
18
22
|
end
|
19
23
|
end
|
@@ -76,7 +76,6 @@ describe Maestrano::Connector::Rails::SubEntityBase do
|
|
76
76
|
let!(:connec_client) { Maestrano::Connec::Client[organization.tenant].new(organization.uid) }
|
77
77
|
let!(:external_client) { Object.new }
|
78
78
|
let(:opts) { {} }
|
79
|
-
subject { Maestrano::Connector::Rails::Entity.new(organization, connec_client, external_client, opts) }
|
80
79
|
subject { Maestrano::Connector::Rails::SubEntityBase.new(organization, connec_client, external_client, opts) }
|
81
80
|
|
82
81
|
describe 'map_to' do
|
data/spec/spec_helper.rb
CHANGED
@@ -20,4 +20,10 @@ RSpec.configure do |config|
|
|
20
20
|
config.order = "random"
|
21
21
|
config.include FactoryGirl::Syntax::Methods
|
22
22
|
config.include Maestrano::Connector::Rails::Engine.routes.url_helpers
|
23
|
-
|
23
|
+
|
24
|
+
config.before(:each) do
|
25
|
+
allow(Maestrano::Connector::Rails::External).to receive(:external_name).and_return('External app')
|
26
|
+
allow(Maestrano::Connector::Rails::External).to receive(:get_client).and_return(Object.new)
|
27
|
+
allow(Maestrano::Connector::Rails::External).to receive(:entities_list).and_return(%w(entity1 entity2))
|
28
|
+
end
|
29
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: maestrano-connector-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pierre Berard
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-07-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: maestrano-rails
|
@@ -284,7 +284,9 @@ files:
|
|
284
284
|
- app/controllers/maestrano/application_controller.rb
|
285
285
|
- app/controllers/maestrano/auth/saml_controller.rb
|
286
286
|
- app/controllers/maestrano/connec_controller.rb
|
287
|
+
- app/controllers/maestrano/dependancies_controller.rb
|
287
288
|
- app/controllers/maestrano/sessions_controller.rb
|
289
|
+
- app/controllers/maestrano/synchronizations_controller.rb
|
288
290
|
- app/helpers/maestrano/connector/rails/session_helper.rb
|
289
291
|
- app/jobs/maestrano/connector/rails/all_synchronizations_job.rb
|
290
292
|
- app/jobs/maestrano/connector/rails/push_to_connec_job.rb
|
@@ -294,11 +296,13 @@ files:
|
|
294
296
|
- app/models/maestrano/connector/rails/concerns/connec_helper.rb
|
295
297
|
- app/models/maestrano/connector/rails/concerns/connector_logger.rb
|
296
298
|
- app/models/maestrano/connector/rails/concerns/entity.rb
|
299
|
+
- app/models/maestrano/connector/rails/concerns/entity_base.rb
|
297
300
|
- app/models/maestrano/connector/rails/concerns/external.rb
|
298
301
|
- app/models/maestrano/connector/rails/concerns/sub_entity_base.rb
|
299
302
|
- app/models/maestrano/connector/rails/connec_helper.rb
|
300
303
|
- app/models/maestrano/connector/rails/connector_logger.rb
|
301
304
|
- app/models/maestrano/connector/rails/entity.rb
|
305
|
+
- app/models/maestrano/connector/rails/entity_base.rb
|
302
306
|
- app/models/maestrano/connector/rails/external.rb
|
303
307
|
- app/models/maestrano/connector/rails/id_map.rb
|
304
308
|
- app/models/maestrano/connector/rails/organization.rb
|
@@ -354,8 +358,10 @@ files:
|
|
354
358
|
- maestrano.png
|
355
359
|
- release_notes.md
|
356
360
|
- spec/controllers/connec_controller_spec.rb
|
361
|
+
- spec/controllers/dependancies_controller_spec.rb
|
357
362
|
- spec/controllers/group_users_controller_spec.rb
|
358
363
|
- spec/controllers/groups_controller_spec.rb
|
364
|
+
- spec/controllers/synchronizations_controller_spec.rb
|
359
365
|
- spec/dummy/README.md
|
360
366
|
- spec/dummy/Rakefile
|
361
367
|
- spec/dummy/app/assets/images/.keep
|
@@ -370,9 +376,7 @@ files:
|
|
370
376
|
- spec/dummy/app/mailers/.keep
|
371
377
|
- spec/dummy/app/models/.keep
|
372
378
|
- spec/dummy/app/models/concerns/.keep
|
373
|
-
- spec/dummy/app/models/entities
|
374
|
-
- spec/dummy/app/models/maestrano/connector/rails/entity.rb
|
375
|
-
- spec/dummy/app/models/maestrano/connector/rails/external.rb
|
379
|
+
- spec/dummy/app/models/entities/.keep
|
376
380
|
- spec/dummy/app/views/home/index.html.erb
|
377
381
|
- spec/dummy/app/views/layouts/application.html.erb
|
378
382
|
- spec/dummy/bin/bundle
|
@@ -422,6 +426,7 @@ files:
|
|
422
426
|
- spec/models/complex_entity_spec.rb
|
423
427
|
- spec/models/connec_helper_spec.rb
|
424
428
|
- spec/models/connector_logger_spec.rb
|
429
|
+
- spec/models/entity_base_spec.rb
|
425
430
|
- spec/models/entity_spec.rb
|
426
431
|
- spec/models/external_spec.rb
|
427
432
|
- spec/models/id_map_spec.rb
|
@@ -1,26 +0,0 @@
|
|
1
|
-
# TODO
|
2
|
-
# This file is provided as an example and should be removed
|
3
|
-
# One such file needs to be created for each synchronizable entity,
|
4
|
-
# with its associated mapper
|
5
|
-
|
6
|
-
# class Entities::ExampleEntity < Maestrano::Connector::Rails::Entity
|
7
|
-
# def connec_entity_name
|
8
|
-
# 'ExampleEntity'
|
9
|
-
# end
|
10
|
-
|
11
|
-
# def external_entity_name
|
12
|
-
# 'Contact'
|
13
|
-
# end
|
14
|
-
|
15
|
-
# def mapper_class
|
16
|
-
# ExampleEntityMapper
|
17
|
-
# end
|
18
|
-
# end
|
19
|
-
|
20
|
-
# class ExampleEntityMapper < Maestrano::Connector::Rails::GenericMapper
|
21
|
-
# extend HashMapper
|
22
|
-
|
23
|
-
# map from('/title'), to('/Salutation')
|
24
|
-
# map from('/first_name'), to('/FirstName')
|
25
|
-
# map from('address_work/billing2/city'), to('City')
|
26
|
-
# end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
class Maestrano::Connector::Rails::External
|
2
|
-
include Maestrano::Connector::Rails::Concerns::External
|
3
|
-
|
4
|
-
def self.external_name
|
5
|
-
'Dummy app'
|
6
|
-
end
|
7
|
-
|
8
|
-
def self.get_client(organization)
|
9
|
-
nil
|
10
|
-
end
|
11
|
-
|
12
|
-
# Return an array of all the entities that the connector can synchronize
|
13
|
-
# If you add new entities, you need to generate
|
14
|
-
# a migration to add them to existing organizations
|
15
|
-
def self.entities_list
|
16
|
-
%w(entity1 entity2)
|
17
|
-
end
|
18
|
-
end
|