rails_workflow 0.4.4 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/concerns/rails_workflow/status.rb +4 -0
- data/app/concerns/rails_workflow/user/assignment.rb +1 -0
- data/app/controllers/rails_workflow/operation_templates_controller.rb +25 -29
- data/app/controllers/rails_workflow/operations_controller.rb +1 -1
- data/app/controllers/rails_workflow/process_templates_controller.rb +1 -1
- data/app/controllers/rails_workflow/processes_controller.rb +1 -1
- data/app/models/rails_workflow/event_operation.rb +15 -0
- data/app/models/rails_workflow/operation.rb +13 -3
- data/app/models/rails_workflow/operation_template.rb +14 -0
- data/app/models/rails_workflow/process.rb +4 -2
- data/app/views/rails_workflow/operation_templates/_event_form.html.slim +43 -0
- data/lib/rails_workflow/config.rb +3 -0
- data/lib/rails_workflow/error_resolver.rb +1 -1
- data/lib/rails_workflow/event_manager.rb +61 -0
- data/lib/rails_workflow/operation_builder.rb +1 -0
- data/lib/rails_workflow/version.rb +1 -1
- data/spec/dummy/log/test.log +0 -0
- data/spec/factories/operation_templates.rb +12 -0
- data/spec/lib/error_resolver_spec.rb +2 -2
- data/spec/lib/event_manager_spec.rb +111 -0
- data/spec/lib/process_builder/events_spec.rb +31 -0
- data/spec/lib/process_manager_spec.rb +5 -3
- data/spec/lib/process_runner/events_spec.rb +72 -0
- data/spec/support/{rails_workflow/prepare_template.rb → contexts/process_template.rb} +1 -1
- data/spec/support/contexts/process_template_with_events.rb +36 -0
- data/spec/support/rails_workflow/custom_operation_template.rb +2 -0
- metadata +15 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab9b0acda56c082f4ede75be038abc2b4e587d97
|
4
|
+
data.tar.gz: a80bd0d24eef6b2a33e345eca16403a977d1d61f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cd6d57faeb02da76cacad1e3deeda66b2006af1ccb22980e82868cf859249293f8b7ce2beef6a1b19fcad8fc3ac986efa1902ad069ed4be825c57b1aff734e72
|
7
|
+
data.tar.gz: 5ac05170290e1b2997095cc20a64216eb01b47fe4b65a661933383db1a6487a611ff1ff27d4a94099a2fbb6a373ba3450cb2555c3d6e068471d036ae4094018f
|
@@ -1,19 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module RailsWorkflow
|
4
|
+
# Used in configuration UI to CRUD operation templates
|
4
5
|
class OperationTemplatesController < ApplicationController
|
5
6
|
layout 'rails_workflow/application'
|
6
7
|
before_action :set_operation_template, only: %i[show edit update destroy]
|
7
8
|
before_action :set_process_template
|
8
9
|
respond_to :html
|
9
10
|
|
10
|
-
|
11
|
+
before_action do
|
11
12
|
@config_section_active = true
|
12
13
|
end
|
13
14
|
|
14
15
|
def index
|
15
|
-
@operation_templates =
|
16
|
-
|
16
|
+
@operation_templates =
|
17
|
+
OperationTemplateDecorator
|
18
|
+
.decorate_collection(operation_templates_collection)
|
17
19
|
end
|
18
20
|
|
19
21
|
def new
|
@@ -22,7 +24,9 @@ module RailsWorkflow
|
|
22
24
|
end
|
23
25
|
|
24
26
|
def create
|
25
|
-
@operation_template =
|
27
|
+
@operation_template =
|
28
|
+
@process_template.operations.create(permitted_params)
|
29
|
+
|
26
30
|
redirect_to process_template_operation_templates_url
|
27
31
|
end
|
28
32
|
|
@@ -38,28 +42,18 @@ module RailsWorkflow
|
|
38
42
|
|
39
43
|
protected
|
40
44
|
|
45
|
+
def permitted_attributes
|
46
|
+
[
|
47
|
+
:kind, :type, :tag, :instruction, :title,
|
48
|
+
:source, :multiple, :child_process_id,
|
49
|
+
:operation_class, :role, :partial_name, :async,
|
50
|
+
:is_background, :group,
|
51
|
+
dependencies: [:id, statuses: []]
|
52
|
+
]
|
53
|
+
end
|
54
|
+
|
41
55
|
def permitted_params
|
42
|
-
parameters =
|
43
|
-
params.permit(
|
44
|
-
operation_template: [
|
45
|
-
:kind,
|
46
|
-
:type,
|
47
|
-
:tag,
|
48
|
-
:instruction,
|
49
|
-
:title, :source,
|
50
|
-
:child_process_id,
|
51
|
-
:operation_class,
|
52
|
-
:role,
|
53
|
-
:partial_name,
|
54
|
-
:async,
|
55
|
-
:is_background,
|
56
|
-
:group,
|
57
|
-
dependencies: [
|
58
|
-
:id,
|
59
|
-
statuses: []
|
60
|
-
]
|
61
|
-
]
|
62
|
-
)
|
56
|
+
parameters = params.permit(operation_template: permitted_attributes)
|
63
57
|
|
64
58
|
if parameters[:operation_template].present?
|
65
59
|
parameters[:operation_template][:dependencies] =
|
@@ -77,17 +71,19 @@ module RailsWorkflow
|
|
77
71
|
def parse_dependencies(hash)
|
78
72
|
hash.values.each do |dep|
|
79
73
|
dep['id'] = dep['id'].to_i
|
80
|
-
dep['statuses'] = dep['statuses'].map(&:to_i) ||
|
74
|
+
dep['statuses'] = dep['statuses'].map(&:to_i) ||
|
75
|
+
RailsWorkflow::OperationTemplate.all_statuses
|
81
76
|
end
|
82
77
|
end
|
83
78
|
|
84
79
|
def operation_templates_collection
|
85
|
-
@operation_templates = @process_template.try(:operations) ||
|
86
|
-
.order(id: :asc)
|
80
|
+
@operation_templates = @process_template.try(:operations) ||
|
81
|
+
OperationTemplate.order(id: :asc)
|
87
82
|
end
|
88
83
|
|
89
84
|
def set_process_template
|
90
|
-
@process_template = ProcessTemplate
|
85
|
+
@process_template = ProcessTemplate
|
86
|
+
.find(params[:process_template_id]).decorate
|
91
87
|
end
|
92
88
|
|
93
89
|
def set_operation_template
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsWorkflow
|
4
|
+
# Event operation - waiting/listening for some event.
|
5
|
+
class EventOperation < Operation
|
6
|
+
def can_start?
|
7
|
+
false
|
8
|
+
end
|
9
|
+
|
10
|
+
# TODO: check if redundant
|
11
|
+
def can_be_assigned?(_user)
|
12
|
+
false # any user can complete operation
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -7,22 +7,32 @@ module RailsWorkflow
|
|
7
7
|
class Operation < ActiveRecord::Base
|
8
8
|
include OperationStatus
|
9
9
|
include Operations::Dependencies
|
10
|
+
# TODO: move to UserOperation
|
10
11
|
include Operations::Assignments
|
11
12
|
include HasContext
|
12
13
|
|
13
14
|
belongs_to :process, class_name: 'RailsWorkflow::Process'
|
14
15
|
alias parent process
|
15
16
|
belongs_to :template, class_name: 'RailsWorkflow::OperationTemplate'
|
16
|
-
belongs_to :child_process,
|
17
|
+
belongs_to :child_process,
|
18
|
+
class_name: 'RailsWorkflow::Process', required: false
|
17
19
|
has_many :workflow_errors, class_name: 'RailsWorkflow::Error', as: :parent
|
18
20
|
|
19
21
|
delegate :data, to: :context
|
20
|
-
delegate :role, to: :template
|
21
|
-
delegate :group, to: :template
|
22
|
+
delegate :role, :multiple?, :group, to: :template
|
22
23
|
delegate :start, :complete, :skip, :cancel, to: :runner
|
23
24
|
|
24
25
|
scope :with_child_process, -> { where.not(child_process: nil) }
|
25
26
|
scope :uncompleted, -> { where(status: user_ready_statuses) }
|
27
|
+
scope :events, lambda {
|
28
|
+
joins(:template)
|
29
|
+
.where(rails_workflow_operation_templates: { kind: 'event' })
|
30
|
+
}
|
31
|
+
|
32
|
+
scope :without_events, lambda {
|
33
|
+
joins(:template)
|
34
|
+
.where.not(rails_workflow_operation_templates: { kind: 'event' })
|
35
|
+
}
|
26
36
|
|
27
37
|
def instruction
|
28
38
|
template.instruction
|
@@ -5,8 +5,11 @@ module RailsWorkflow
|
|
5
5
|
include OperationStatus
|
6
6
|
include RailsWorkflow::Uuid
|
7
7
|
include OperationTemplates::Dependencies
|
8
|
+
# TODO: move to separate UserOperationTemplate
|
8
9
|
include OperationTemplates::Assignments
|
9
10
|
|
11
|
+
serialize :source, JSON
|
12
|
+
|
10
13
|
belongs_to :process_template, class_name: 'RailsWorkflow::ProcessTemplate'
|
11
14
|
belongs_to :child_process, class_name: 'RailsWorkflow::ProcessTemplate', required: false
|
12
15
|
|
@@ -19,6 +22,17 @@ module RailsWorkflow
|
|
19
22
|
OperationTemplate.other_operations(process_template_id, id)
|
20
23
|
end
|
21
24
|
|
25
|
+
def multiple=(value)
|
26
|
+
self.source ||= {}
|
27
|
+
source[:multiple] = value == 'true'
|
28
|
+
end
|
29
|
+
|
30
|
+
def multiple?
|
31
|
+
(source || {})['multiple'] == true
|
32
|
+
end
|
33
|
+
|
34
|
+
alias multiple multiple?
|
35
|
+
|
22
36
|
class << self
|
23
37
|
def types
|
24
38
|
RailsWorkflow.config.operation_types
|
@@ -9,6 +9,8 @@ module RailsWorkflow
|
|
9
9
|
|
10
10
|
belongs_to :template, class_name: 'RailsWorkflow::ProcessTemplate'
|
11
11
|
has_many :operations, class_name: 'RailsWorkflow::Operation'
|
12
|
+
delegate :events, to: :operations, allow_nil: true
|
13
|
+
|
12
14
|
has_one :parent_operation,
|
13
15
|
class_name: 'RailsWorkflow::Operation',
|
14
16
|
foreign_key: :child_process_id
|
@@ -39,13 +41,13 @@ module RailsWorkflow
|
|
39
41
|
|
40
42
|
def uncompleted?
|
41
43
|
uncompleted_statuses.include?(status) &&
|
42
|
-
uncompleted_operations.size.zero?
|
44
|
+
uncompleted_operations.reject(&:async).size.zero?
|
43
45
|
end
|
44
46
|
|
45
47
|
# Returns set or operation that not yet completed.
|
46
48
|
# Operation complete in DONE, SKIPPED, CANCELED, etc many other statuses
|
47
49
|
def uncompleted_operations
|
48
|
-
operations.reject(&:completed?)
|
50
|
+
operations(true).reject(&:completed?)
|
49
51
|
end
|
50
52
|
|
51
53
|
def can_start?
|
@@ -0,0 +1,43 @@
|
|
1
|
+
- if @operation_template.errors.any?
|
2
|
+
#error_explanation
|
3
|
+
h2 = "#{pluralize(@operation_template.errors.count, "error")} prohibited this wf_operation_template from being saved:"
|
4
|
+
ul
|
5
|
+
- @operation_template.errors.full_messages.each do |message|
|
6
|
+
li = message
|
7
|
+
|
8
|
+
= hidden_field_tag 'operation_template[kind]', @operation_template.kind
|
9
|
+
|
10
|
+
.form-group
|
11
|
+
= f.label :title, class: "control-label col-sm-2"
|
12
|
+
.col-sm-10
|
13
|
+
= f.text_field :title, class: "form-control"
|
14
|
+
|
15
|
+
|
16
|
+
.form-group
|
17
|
+
= f.label :operation_class, class: "control-label col-sm-2"
|
18
|
+
.col-sm-10
|
19
|
+
= f.text_field :operation_class, class: "form-control", placeholder: f.object.default_class
|
20
|
+
|
21
|
+
.form-group
|
22
|
+
= f.label :type, "Template Class", class: "control-label col-sm-2"
|
23
|
+
.col-sm-10
|
24
|
+
= f.text_field :type, class: "form-control", placeholder: f.object.default_type
|
25
|
+
|
26
|
+
.form-group
|
27
|
+
= f.label :partial_name, "Context Partial", class: "control-label col-sm-2"
|
28
|
+
.col-sm-10
|
29
|
+
= f.text_field :partial_name, class: "form-control", placeholder: "Default"
|
30
|
+
|
31
|
+
.form-group
|
32
|
+
= f.label :tag, "Event Tag", class: "control-label col-sm-2"
|
33
|
+
.col-sm-10
|
34
|
+
= f.text_field :tag, class: "form-control"
|
35
|
+
|
36
|
+
.form-group
|
37
|
+
.col-sm-2
|
38
|
+
.col-sm-10
|
39
|
+
.checkbox
|
40
|
+
label
|
41
|
+
= f.check_box :multiple, {}, 'true', 'false'
|
42
|
+
strong
|
43
|
+
= 'Multiple'
|
@@ -17,6 +17,7 @@ require_relative './process_runner'
|
|
17
17
|
require_relative './operation_runner'
|
18
18
|
require_relative './dependency_resolver'
|
19
19
|
require_relative './process_manager'
|
20
|
+
require_relative './event_manager'
|
20
21
|
require 'rails_workflow/db/pg'
|
21
22
|
|
22
23
|
module RailsWorkflow
|
@@ -133,6 +134,8 @@ module RailsWorkflow
|
|
133
134
|
@default_operation_types = {
|
134
135
|
default: { title: 'Default Operation',
|
135
136
|
class: 'RailsWorkflow::Operation' },
|
137
|
+
event: { title: 'Event',
|
138
|
+
class: 'RailsWorkflow::EventOperation' },
|
136
139
|
user: { title: 'User Operation',
|
137
140
|
class: 'RailsWorkflow::UserOperation' },
|
138
141
|
user_role: { title: 'Operation for User By Role',
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsWorkflow
|
4
|
+
# This manager controls events processing. Searches matching event operations
|
5
|
+
# for a given event and merges event context to matched event operations.
|
6
|
+
class EventManager
|
7
|
+
class << self
|
8
|
+
def create_event(tag, context = {})
|
9
|
+
new(tag, context).handle
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(tag, context = {})
|
14
|
+
@tag = tag
|
15
|
+
@context = context
|
16
|
+
end
|
17
|
+
|
18
|
+
def handle
|
19
|
+
event_operations.each do |event_operation|
|
20
|
+
next if not_matches(event_operation)
|
21
|
+
|
22
|
+
process_multiple_event(event_operation)
|
23
|
+
event_operation.data.merge!(@context)
|
24
|
+
event_operation.complete
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def process_multiple_event(event_operation)
|
31
|
+
return unless event_operation.multiple?
|
32
|
+
|
33
|
+
new_event_operation = operation_builder.new(
|
34
|
+
event_operation.process, event_operation.template, [event_operation]
|
35
|
+
).create_operation
|
36
|
+
|
37
|
+
new_event_operation.start
|
38
|
+
end
|
39
|
+
|
40
|
+
def not_matches(event_operation)
|
41
|
+
event_operation.respond_to?(:match) && !event_operation.match(@context)
|
42
|
+
end
|
43
|
+
|
44
|
+
def event_operations
|
45
|
+
EventOperation.where(tag: @tag, status: Status::WAITING).all
|
46
|
+
end
|
47
|
+
|
48
|
+
# TODO: refactor all operation_builder, and other configuration methods
|
49
|
+
def operation_builder
|
50
|
+
config.operation_builder
|
51
|
+
end
|
52
|
+
|
53
|
+
def operation_runner
|
54
|
+
config.operation_runner
|
55
|
+
end
|
56
|
+
|
57
|
+
def config
|
58
|
+
RailsWorkflow.config
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/spec/dummy/log/test.log
CHANGED
Binary file
|
@@ -5,11 +5,23 @@ FactoryGirl.define do
|
|
5
5
|
title 'Operation Template'
|
6
6
|
kind 'default'
|
7
7
|
type nil
|
8
|
+
async nil
|
8
9
|
is_background true
|
9
10
|
association :process_template, factory: :process_template
|
10
11
|
|
11
12
|
factory :parent_operation_template do
|
12
13
|
child_process { create :process_template }
|
13
14
|
end
|
15
|
+
|
16
|
+
factory :user_operation_template do
|
17
|
+
title 'User Operation'
|
18
|
+
kind 'user'
|
19
|
+
end
|
20
|
+
|
21
|
+
factory :event do
|
22
|
+
title 'Event'
|
23
|
+
kind 'event'
|
24
|
+
tag 'event'
|
25
|
+
end
|
14
26
|
end
|
15
27
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'rails_helper'
|
4
|
-
require_relative '../support/
|
4
|
+
require_relative '../support/contexts/process_template'
|
5
5
|
|
6
6
|
module RailsWorkflow
|
7
7
|
RSpec.describe ErrorResolver do
|
8
|
-
|
8
|
+
include_context 'process template'
|
9
9
|
|
10
10
|
let(:template) { prepare_template }
|
11
11
|
let(:process_manager) do
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
require_relative './../support/contexts/process_template_with_events'
|
5
|
+
|
6
|
+
module RailsWorkflow
|
7
|
+
RSpec.describe EventManager do
|
8
|
+
include_context 'process template with events'
|
9
|
+
|
10
|
+
it 'ignores not waiting events' do
|
11
|
+
expect { described_class.create_event(:first_event, a: 'b') }
|
12
|
+
.not_to change { process.events.first.status }
|
13
|
+
.from(Status::NOT_STARTED)
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when process started' do
|
17
|
+
before { process_manager.start_process }
|
18
|
+
|
19
|
+
it 'merges event context to event operation context' do
|
20
|
+
described_class.create_event(:first_event, a: 'b')
|
21
|
+
expect(process.events.first.data).to include(a: 'b')
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'merges event context to next operations' do
|
25
|
+
described_class.create_event(:first_event, a: 'b')
|
26
|
+
new_operations = dependent_operations(process, process.events.first)
|
27
|
+
|
28
|
+
new_operations.each do |new_operation|
|
29
|
+
expect(new_operation.data).to include(a: 'b')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'multiple event operation' do
|
35
|
+
# TODO: if first event operation failed to complete - should
|
36
|
+
# not affect other event operations for same event
|
37
|
+
before do
|
38
|
+
first_event_template.first.update(source: { multiple: true })
|
39
|
+
process_manager.start_process
|
40
|
+
end
|
41
|
+
|
42
|
+
let(:first_event_template) do
|
43
|
+
template.operations.where(tag: :first_event)
|
44
|
+
end
|
45
|
+
let(:first_event_operations) { process.events.where(tag: :first_event) }
|
46
|
+
|
47
|
+
it 'creates new event operation' do
|
48
|
+
expect { described_class.create_event(:first_event, a: 'b') }
|
49
|
+
.to change { first_event_operations.count }.from(1).to(2)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'new event operation has waiting status' do
|
53
|
+
expect { described_class.create_event(:first_event, a: 'b') }
|
54
|
+
.not_to change {
|
55
|
+
first_event_operations.where(status: Status::WAITING).count
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should not affect next event operations context'
|
60
|
+
end
|
61
|
+
|
62
|
+
describe 'event matching' do
|
63
|
+
context 'matches event to event operation' do
|
64
|
+
let(:custom_event_operation) do
|
65
|
+
Class.new(EventOperation) do
|
66
|
+
def match(event_context)
|
67
|
+
event_context[:check] == true
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
let(:first_event) { process.events.where(tag: :first_event).first }
|
72
|
+
let(:first_event_template) do
|
73
|
+
OperationTemplate.where(tag: :first_event).first
|
74
|
+
end
|
75
|
+
|
76
|
+
before do
|
77
|
+
stub_const('CustomEventOperation', custom_event_operation)
|
78
|
+
|
79
|
+
first_event_template.update(operation_class: 'CustomEventOperation')
|
80
|
+
process_manager.start_process
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'ignores not matching event' do
|
84
|
+
expect { described_class.create_event(:first_event, check: false) }
|
85
|
+
.not_to change { first_event.reload.status }
|
86
|
+
.from(Status::WAITING)
|
87
|
+
|
88
|
+
expect { described_class.create_event(:first_event, {}) }
|
89
|
+
.not_to change { first_event.reload.status }
|
90
|
+
.from(Status::WAITING)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'catches matching event' do
|
94
|
+
described_class.create_event(:first_event, check: true)
|
95
|
+
|
96
|
+
expect { described_class.create_event(:first_event, check: true) }
|
97
|
+
.not_to change { first_event.reload.status }
|
98
|
+
.from(Status::DONE)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def dependent_operations(process, completed_operation)
|
104
|
+
process.operations.reload.select do |operation|
|
105
|
+
operation.dependencies.any? do |dependency|
|
106
|
+
dependency['operation_id'] == completed_operation.id
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
require_relative './../../support/contexts/process_template_with_events'
|
5
|
+
|
6
|
+
module RailsWorkflow
|
7
|
+
RSpec.describe ProcessBuilder do
|
8
|
+
include_context 'process template with events'
|
9
|
+
|
10
|
+
context 'independent event' do
|
11
|
+
it 'creates two operations' do
|
12
|
+
# first independent operation and first event
|
13
|
+
expect(process.operations.size).to eq 2
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'creates event' do
|
17
|
+
expect(process.events.size).to eq 1
|
18
|
+
end
|
19
|
+
|
20
|
+
it do
|
21
|
+
expect(process.events.first.status)
|
22
|
+
.to eq RailsWorkflow::Status::NOT_STARTED
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'creates event context' do
|
26
|
+
event = process.events.first
|
27
|
+
expect(event.data).to include(some: 'value')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'rails_helper'
|
4
|
-
require_relative '../support/
|
4
|
+
require_relative '../support/contexts/process_template'
|
5
5
|
|
6
6
|
module RailsWorkflow
|
7
7
|
RSpec.describe ProcessManager do
|
8
|
-
|
8
|
+
include_context 'process template'
|
9
9
|
|
10
10
|
let(:template) { prepare_template }
|
11
11
|
|
@@ -46,7 +46,9 @@ module RailsWorkflow
|
|
46
46
|
before :each do
|
47
47
|
allow_any_instance_of(RailsWorkflow::ProcessManager)
|
48
48
|
.to receive(:complete_process)
|
49
|
-
allow_any_instance_of(RailsWorkflow::OperationRunner)
|
49
|
+
allow_any_instance_of(RailsWorkflow::OperationRunner)
|
50
|
+
.to receive(:complete)
|
51
|
+
|
50
52
|
process_manager = RailsWorkflow::ProcessManager.new process
|
51
53
|
process_manager.start_process
|
52
54
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
require_relative './../../support/contexts/process_template_with_events'
|
5
|
+
|
6
|
+
module RailsWorkflow
|
7
|
+
RSpec.describe ProcessRunner do
|
8
|
+
include_context 'process template with events'
|
9
|
+
|
10
|
+
it 'sets not started events to waiting status' do
|
11
|
+
expect { process_manager.start_process }
|
12
|
+
.to change { process.events.first.status }
|
13
|
+
.from(Status::NOT_STARTED).to(Status::WAITING)
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'for started process' do
|
17
|
+
before { process_manager.start_process }
|
18
|
+
|
19
|
+
it 'event operation catches event' do
|
20
|
+
expect { EventManager.create_event(:first_event, a: 'b') }
|
21
|
+
.to change { process.events.first.status }
|
22
|
+
.from(Status::WAITING).to(Status::DONE)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'process waits for last sync event' do
|
26
|
+
process.operations.without_events.first.complete
|
27
|
+
|
28
|
+
expect { process.operations.without_events.first.complete }
|
29
|
+
.not_to change { process.status }.from(Status::IN_PROGRESS)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'last sync event finishes process' do
|
33
|
+
process.operations.without_events.first.complete
|
34
|
+
process.operations.without_events.last.complete
|
35
|
+
|
36
|
+
EventManager.create_event(:first_event, a: 'b')
|
37
|
+
|
38
|
+
expect { EventManager.create_event(:second_event, c: 'd') }
|
39
|
+
.to change { process.reload.status }
|
40
|
+
.from(Status::IN_PROGRESS).to(Status::DONE)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'first sync event finishes process' do
|
44
|
+
process.operations.without_events.first.complete
|
45
|
+
process.operations.without_events.last.complete
|
46
|
+
|
47
|
+
EventManager.create_event(:second_event, a: 'b')
|
48
|
+
|
49
|
+
# Now first operation is only not yet finished operation
|
50
|
+
# and we finish it by sending this event
|
51
|
+
expect { EventManager.create_event(:first_event, c: 'd') }
|
52
|
+
.to change { process.reload.status }
|
53
|
+
.from(Status::IN_PROGRESS).to(Status::DONE)
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'with async event' do
|
57
|
+
before do
|
58
|
+
OperationTemplate.where(tag: :second_event).first.update(async: true)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'process does not wait for async' do
|
62
|
+
process.operations.without_events.first.complete
|
63
|
+
process.operations.without_events.last.complete
|
64
|
+
|
65
|
+
expect { EventManager.create_event(:first_event, c: 'd') }
|
66
|
+
.to change { process.reload.status }
|
67
|
+
.from(Status::IN_PROGRESS).to(Status::DONE)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsWorkflow
|
4
|
+
RSpec.shared_context 'process template with events' do
|
5
|
+
let!(:template) { prepare_template }
|
6
|
+
|
7
|
+
let(:process) { ProcessManager.create_process template.id, some: 'value' }
|
8
|
+
let(:operation_runner) { RailsWorkflow::OperationRunner }
|
9
|
+
let(:process_manager) { RailsWorkflow::ProcessManager.new process }
|
10
|
+
|
11
|
+
def prepare_template_operations(template)
|
12
|
+
operation = create :user_operation_template, process_template: template
|
13
|
+
event = create :event, tag: 'first_event', process_template: template
|
14
|
+
|
15
|
+
template_options = {
|
16
|
+
process_template: template,
|
17
|
+
dependencies: prepare_template_dependencies(operation, event)
|
18
|
+
}
|
19
|
+
|
20
|
+
# second event
|
21
|
+
create :event, template_options.merge(tag: 'second_event')
|
22
|
+
create :user_operation_template, template_options
|
23
|
+
end
|
24
|
+
|
25
|
+
def prepare_template_dependencies(operation, event)
|
26
|
+
[{ 'id' => operation.id, 'statuses' => [RailsWorkflow::Status::DONE] },
|
27
|
+
{ 'id' => event.id, 'statuses' => [RailsWorkflow::Status::DONE] }]
|
28
|
+
end
|
29
|
+
|
30
|
+
def prepare_template
|
31
|
+
template = create :process_template
|
32
|
+
prepare_template_operations(template)
|
33
|
+
template
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_workflow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Maxim Madzhuga
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-11-
|
11
|
+
date: 2017-11-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -219,6 +219,7 @@ files:
|
|
219
219
|
- app/jobs/rails_workflow/operation_execution_job.rb
|
220
220
|
- app/models/rails_workflow/context.rb
|
221
221
|
- app/models/rails_workflow/error.rb
|
222
|
+
- app/models/rails_workflow/event_operation.rb
|
222
223
|
- app/models/rails_workflow/operation.rb
|
223
224
|
- app/models/rails_workflow/operation_template.rb
|
224
225
|
- app/models/rails_workflow/process.rb
|
@@ -234,6 +235,7 @@ files:
|
|
234
235
|
- app/views/application/_flash.html.slim
|
235
236
|
- app/views/layouts/rails_workflow/application.html.slim
|
236
237
|
- app/views/rails_workflow/operation_templates/_default_form.html.slim
|
238
|
+
- app/views/rails_workflow/operation_templates/_event_form.html.slim
|
237
239
|
- app/views/rails_workflow/operation_templates/_user_form.html.slim
|
238
240
|
- app/views/rails_workflow/operation_templates/_user_group_form.html.slim
|
239
241
|
- app/views/rails_workflow/operation_templates/_user_role_form.html.slim
|
@@ -266,6 +268,7 @@ files:
|
|
266
268
|
- lib/rails_workflow/engine.rb
|
267
269
|
- lib/rails_workflow/error_builder.rb
|
268
270
|
- lib/rails_workflow/error_resolver.rb
|
271
|
+
- lib/rails_workflow/event_manager.rb
|
269
272
|
- lib/rails_workflow/operation_builder.rb
|
270
273
|
- lib/rails_workflow/operation_runner.rb
|
271
274
|
- lib/rails_workflow/process_builder.rb
|
@@ -520,9 +523,12 @@ files:
|
|
520
523
|
- spec/features/process_template_spec.rb
|
521
524
|
- spec/lib/error_builder_spec.rb
|
522
525
|
- spec/lib/error_resolver_spec.rb
|
526
|
+
- spec/lib/event_manager_spec.rb
|
523
527
|
- spec/lib/operation_builder_spec.rb
|
528
|
+
- spec/lib/process_builder/events_spec.rb
|
524
529
|
- spec/lib/process_builder_spec.rb
|
525
530
|
- spec/lib/process_manager_spec.rb
|
531
|
+
- spec/lib/process_runner/events_spec.rb
|
526
532
|
- spec/models/rails_workflow/context_spec.rb
|
527
533
|
- spec/models/rails_workflow/error_spec.rb
|
528
534
|
- spec/models/rails_workflow/operation_spec.rb
|
@@ -533,6 +539,8 @@ files:
|
|
533
539
|
- spec/serializers/process_template_serializer_spec.rb
|
534
540
|
- spec/services/process_importer_spec.rb
|
535
541
|
- spec/spec_helper.rb
|
542
|
+
- spec/support/contexts/process_template.rb
|
543
|
+
- spec/support/contexts/process_template_with_events.rb
|
536
544
|
- spec/support/controller_macros.rb
|
537
545
|
- spec/support/jsons/broken_parent_process_template.json
|
538
546
|
- spec/support/jsons/parent_process_template.json
|
@@ -541,7 +549,6 @@ files:
|
|
541
549
|
- spec/support/pages/operations.rb
|
542
550
|
- spec/support/rails_workflow/custom_operation.rb
|
543
551
|
- spec/support/rails_workflow/custom_operation_template.rb
|
544
|
-
- spec/support/rails_workflow/prepare_template.rb
|
545
552
|
- spec/support/workflow_helper.rb
|
546
553
|
homepage: https://github.com/madzhuga/rails_workflow
|
547
554
|
licenses:
|
@@ -814,11 +821,14 @@ test_files:
|
|
814
821
|
- spec/dummy/app/views/leads/edit.html.slim
|
815
822
|
- spec/dummy/app/views/layouts/application.html.erb
|
816
823
|
- spec/services/process_importer_spec.rb
|
824
|
+
- spec/lib/process_builder/events_spec.rb
|
817
825
|
- spec/lib/error_resolver_spec.rb
|
818
826
|
- spec/lib/operation_builder_spec.rb
|
819
827
|
- spec/lib/process_builder_spec.rb
|
828
|
+
- spec/lib/process_runner/events_spec.rb
|
820
829
|
- spec/lib/process_manager_spec.rb
|
821
830
|
- spec/lib/error_builder_spec.rb
|
831
|
+
- spec/lib/event_manager_spec.rb
|
822
832
|
- spec/spec_helper.rb
|
823
833
|
- spec/models/rails_workflow/operation_template_spec.rb
|
824
834
|
- spec/models/rails_workflow/operation_spec.rb
|
@@ -832,9 +842,10 @@ test_files:
|
|
832
842
|
- spec/support/jsons/user_operation_template.json
|
833
843
|
- spec/support/jsons/process_template.json
|
834
844
|
- spec/support/jsons/parent_process_template.json
|
835
|
-
- spec/support/rails_workflow/prepare_template.rb
|
836
845
|
- spec/support/rails_workflow/custom_operation_template.rb
|
837
846
|
- spec/support/rails_workflow/custom_operation.rb
|
847
|
+
- spec/support/contexts/process_template_with_events.rb
|
848
|
+
- spec/support/contexts/process_template.rb
|
838
849
|
- spec/support/workflow_helper.rb
|
839
850
|
- spec/support/pages/operations.rb
|
840
851
|
- spec/support/controller_macros.rb
|