maestrano-connector-rails 1.1.2 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|