rails_workflow 0.4.4 → 0.7.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/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
|