-
Notifications
You must be signed in to change notification settings - Fork 161
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'origin/master' into feature/add_from_st…
…ate_to_transition
- Loading branch information
Showing
13 changed files
with
299 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,9 @@ name: tests | |
|
||
on: | ||
push: | ||
branches: | ||
- "master" | ||
pull_request: | ||
|
||
concurrency: | ||
group: ${{ github.workflow }}-${{ github.ref }} | ||
|
@@ -21,12 +24,15 @@ jobs: | |
strategy: | ||
fail-fast: false | ||
matrix: | ||
ruby-version: [2.7, 3.0, 3.1] | ||
ruby-version: ["2.7", "3.0", "3.1", "3.2"] | ||
rails-version: | ||
- "6.1.5" | ||
- "7.0.4" | ||
- "main" | ||
postgres-version: [9.6, 11, 14] | ||
postgres-version: ["9.6", "11", "14"] | ||
exclude: | ||
- ruby-version: "3.2" | ||
rails-version: "6.1.5" | ||
runs-on: ubuntu-latest | ||
services: | ||
postgres: | ||
|
@@ -60,13 +66,15 @@ jobs: | |
strategy: | ||
fail-fast: false | ||
matrix: | ||
ruby-version: [2.7, 3.0, 3.1] | ||
ruby-version: ["2.7", "3.0", "3.1", "3.2"] | ||
rails-version: | ||
- "6.1.5" | ||
- "7.0.4" | ||
- "main" | ||
mysql-version: | ||
- "5.7" | ||
mysql-version: ["5.7", "8.0"] | ||
exclude: | ||
- ruby-version: 3.2 | ||
rails-version: "6.1.5" | ||
runs-on: ubuntu-latest | ||
services: | ||
mysql: | ||
|
@@ -78,6 +86,11 @@ jobs: | |
MYSQL_DATABASE: statesman_test | ||
ports: | ||
- "3306:3306" | ||
options: >- | ||
--health-cmd "mysqladmin ping" | ||
--health-interval 10s | ||
--health-timeout 5s | ||
--health-retries 5 | ||
env: | ||
DATABASE_URL: mysql2://foobar:[email protected]/statesman_test | ||
DATABASE_DEPENDENCY_PORT: "3306" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# frozen_string_literal: true | ||
|
||
module Statesman | ||
module Adapters | ||
module TypeSafeActiveRecordQueries | ||
def configure_state_machine(args = {}) | ||
transition_class = args.fetch(:transition_class) | ||
initial_state = args.fetch(:initial_state) | ||
|
||
include( | ||
ActiveRecordQueries::ClassMethods.new( | ||
transition_class: transition_class, | ||
initial_state: initial_state, | ||
most_recent_transition_alias: try(:most_recent_transition_alias), | ||
transition_name: try(:transition_name), | ||
), | ||
) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
# frozen_string_literal: true | ||
|
||
module Statesman | ||
VERSION = "10.0.0" | ||
VERSION = "10.1.0" | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
208 changes: 208 additions & 0 deletions
208
spec/statesman/adapters/type_safe_active_record_queries_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
# frozen_string_literal: true | ||
|
||
require "spec_helper" | ||
|
||
describe Statesman::Adapters::TypeSafeActiveRecordQueries, active_record: true do | ||
def configure(klass, transition_class) | ||
klass.send(:extend, described_class) | ||
klass.configure_state_machine( | ||
transition_class: transition_class, | ||
initial_state: :initial, | ||
) | ||
end | ||
|
||
before do | ||
prepare_model_table | ||
prepare_transitions_table | ||
prepare_other_model_table | ||
prepare_other_transitions_table | ||
|
||
Statesman.configure do | ||
storage_adapter(Statesman::Adapters::ActiveRecord) | ||
end | ||
end | ||
|
||
after { Statesman.configure { storage_adapter(Statesman::Adapters::Memory) } } | ||
|
||
let!(:model) do | ||
model = MyActiveRecordModel.create | ||
model.state_machine.transition_to(:succeeded) | ||
model | ||
end | ||
|
||
let!(:other_model) do | ||
model = MyActiveRecordModel.create | ||
model.state_machine.transition_to(:failed) | ||
model | ||
end | ||
|
||
let!(:initial_state_model) { MyActiveRecordModel.create } | ||
|
||
let!(:returned_to_initial_model) do | ||
model = MyActiveRecordModel.create | ||
model.state_machine.transition_to(:failed) | ||
model.state_machine.transition_to(:initial) | ||
model | ||
end | ||
|
||
shared_examples "testing methods" do | ||
before do | ||
configure(MyActiveRecordModel, MyActiveRecordModelTransition) | ||
configure(OtherActiveRecordModel, OtherActiveRecordModelTransition) | ||
|
||
MyActiveRecordModel.send(:has_one, :other_active_record_model) | ||
OtherActiveRecordModel.send(:belongs_to, :my_active_record_model) | ||
end | ||
|
||
describe ".in_state" do | ||
context "given a single state" do | ||
subject { MyActiveRecordModel.in_state(:succeeded) } | ||
|
||
it { is_expected.to include model } | ||
it { is_expected.to_not include other_model } | ||
end | ||
|
||
context "given multiple states" do | ||
subject { MyActiveRecordModel.in_state(:succeeded, :failed) } | ||
|
||
it { is_expected.to include model } | ||
it { is_expected.to include other_model } | ||
end | ||
|
||
context "given the initial state" do | ||
subject { MyActiveRecordModel.in_state(:initial) } | ||
|
||
it { is_expected.to include initial_state_model } | ||
it { is_expected.to include returned_to_initial_model } | ||
end | ||
|
||
context "given an array of states" do | ||
subject { MyActiveRecordModel.in_state(%i[succeeded failed]) } | ||
|
||
it { is_expected.to include model } | ||
it { is_expected.to include other_model } | ||
end | ||
|
||
context "merging two queries" do | ||
subject do | ||
MyActiveRecordModel.in_state(:succeeded). | ||
joins(:other_active_record_model). | ||
merge(OtherActiveRecordModel.in_state(:initial)) | ||
end | ||
|
||
it { is_expected.to be_empty } | ||
end | ||
end | ||
|
||
describe ".not_in_state" do | ||
context "given a single state" do | ||
subject { MyActiveRecordModel.not_in_state(:failed) } | ||
|
||
it { is_expected.to include model } | ||
it { is_expected.to_not include other_model } | ||
end | ||
|
||
context "given multiple states" do | ||
subject(:not_in_state) { MyActiveRecordModel.not_in_state(:succeeded, :failed) } | ||
|
||
it do | ||
expect(not_in_state).to contain_exactly(initial_state_model, | ||
returned_to_initial_model) | ||
end | ||
end | ||
|
||
context "given an array of states" do | ||
subject(:not_in_state) { MyActiveRecordModel.not_in_state(%i[succeeded failed]) } | ||
|
||
it do | ||
expect(not_in_state).to contain_exactly(initial_state_model, | ||
returned_to_initial_model) | ||
end | ||
end | ||
end | ||
|
||
context "with a custom name for the transition association" do | ||
before do | ||
# Switch to using OtherActiveRecordModelTransition, so the existing | ||
# relation with MyActiveRecordModelTransition doesn't interfere with | ||
# this spec. | ||
MyActiveRecordModel.send(:has_many, | ||
:custom_name, | ||
class_name: "OtherActiveRecordModelTransition") | ||
|
||
MyActiveRecordModel.class_eval do | ||
def self.transition_class | ||
OtherActiveRecordModelTransition | ||
end | ||
end | ||
end | ||
|
||
describe ".in_state" do | ||
subject(:query) { MyActiveRecordModel.in_state(:succeeded) } | ||
|
||
specify { expect { query }.to_not raise_error } | ||
end | ||
end | ||
|
||
context "with a custom primary key for the model" do | ||
before do | ||
# Switch to using OtherActiveRecordModelTransition, so the existing | ||
# relation with MyActiveRecordModelTransition doesn't interfere with | ||
# this spec. | ||
# Configure the relationship to use a different primary key, | ||
MyActiveRecordModel.send(:has_many, | ||
:custom_name, | ||
class_name: "OtherActiveRecordModelTransition", | ||
primary_key: :external_id) | ||
|
||
MyActiveRecordModel.class_eval do | ||
def self.transition_class | ||
OtherActiveRecordModelTransition | ||
end | ||
end | ||
end | ||
|
||
describe ".in_state" do | ||
subject(:query) { MyActiveRecordModel.in_state(:succeeded) } | ||
|
||
specify { expect { query }.to_not raise_error } | ||
end | ||
end | ||
|
||
context "after_commit transactional integrity" do | ||
before do | ||
MyStateMachine.class_eval do | ||
cattr_accessor(:after_commit_callback_executed) { false } | ||
|
||
after_transition(from: :initial, to: :succeeded, after_commit: true) do | ||
# This leaks state in a testable way if transactional integrity is broken. | ||
MyStateMachine.after_commit_callback_executed = true | ||
end | ||
end | ||
end | ||
|
||
after do | ||
MyStateMachine.class_eval do | ||
callbacks[:after_commit] = [] | ||
end | ||
end | ||
|
||
let!(:model) do | ||
MyActiveRecordModel.create | ||
end | ||
|
||
it do | ||
expect do | ||
ActiveRecord::Base.transaction do | ||
model.state_machine.transition_to!(:succeeded) | ||
raise ActiveRecord::Rollback | ||
end | ||
end.to_not change(MyStateMachine, :after_commit_callback_executed) | ||
end | ||
end | ||
end | ||
|
||
context "using configuration method" do | ||
include_examples "testing methods" | ||
end | ||
end |
Oops, something went wrong.