carbonmu 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +14 -0
  7. data/Gemfile +3 -0
  8. data/Gemfile.lock +161 -0
  9. data/Guardfile +50 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +66 -0
  12. data/Rakefile +10 -0
  13. data/carbonmu.gemspec +64 -0
  14. data/config/i18n-tasks.yml +89 -0
  15. data/config/locales/en.yml +6 -0
  16. data/config/locales/nl.yml +6 -0
  17. data/console +9 -0
  18. data/doc/architecture.png +0 -0
  19. data/lib/carbonmu.rb +42 -0
  20. data/lib/commands/locale_command.rb +12 -0
  21. data/lib/commands/ping_command.rb +9 -0
  22. data/lib/commands/reboot_command.rb +9 -0
  23. data/lib/commands/say_command.rb +10 -0
  24. data/lib/commands/unknown_command.rb +7 -0
  25. data/lib/core/command.rb +26 -0
  26. data/lib/core/command_context.rb +12 -0
  27. data/lib/core/configuration.rb +22 -0
  28. data/lib/core/connection.rb +19 -0
  29. data/lib/core/internationalization.rb +16 -0
  30. data/lib/core/parser.rb +29 -0
  31. data/lib/core/server.rb +118 -0
  32. data/lib/core/server_supervision_group.rb +5 -0
  33. data/lib/core_ext/match_data.rb +7 -0
  34. data/lib/core_ext/string.rb +5 -0
  35. data/lib/edge_router/edge_connection.rb +39 -0
  36. data/lib/edge_router/edge_router.rb +104 -0
  37. data/lib/edge_router/edge_router_supervision_group.rb +5 -0
  38. data/lib/edge_router/telnet_connection.rb +35 -0
  39. data/lib/edge_router/telnet_receptor.rb +30 -0
  40. data/lib/errors.rb +4 -0
  41. data/lib/game_objects/container.rb +10 -0
  42. data/lib/game_objects/exit.rb +8 -0
  43. data/lib/game_objects/game_object.rb +13 -0
  44. data/lib/game_objects/movable.rb +12 -0
  45. data/lib/game_objects/player.rb +17 -0
  46. data/lib/game_objects/room.rb +16 -0
  47. data/lib/game_objects/thing.rb +7 -0
  48. data/lib/interactions/notify.rb +11 -0
  49. data/lib/interactions/reboot.rb +8 -0
  50. data/lib/ipc/carbon_ipc_socket.rb +21 -0
  51. data/lib/ipc/ipc_message.rb +54 -0
  52. data/lib/ipc/read_socket.rb +18 -0
  53. data/lib/ipc/write_socket.rb +12 -0
  54. data/lib/version.rb +7 -0
  55. data/mongoid.yml +12 -0
  56. data/spec/carbonmu_spec.rb +14 -0
  57. data/spec/i18n_spec.rb +18 -0
  58. data/spec/lib/commands/say_command_spec.rb +11 -0
  59. data/spec/lib/core/command_context_spec.rb +16 -0
  60. data/spec/lib/core/command_spec.rb +37 -0
  61. data/spec/lib/core/configuration_spec.rb +37 -0
  62. data/spec/lib/core/connection_spec.rb +46 -0
  63. data/spec/lib/core/internationalization_spec.rb +24 -0
  64. data/spec/lib/core/parser_spec.rb +30 -0
  65. data/spec/lib/core/server_spec.rb +35 -0
  66. data/spec/lib/edge_router/edge_connection_spec.rb +9 -0
  67. data/spec/lib/game_objects/container_spec.rb +9 -0
  68. data/spec/lib/game_objects/exit_spec.rb +7 -0
  69. data/spec/lib/game_objects/game_object_spec.rb +12 -0
  70. data/spec/lib/game_objects/movable_spec.rb +9 -0
  71. data/spec/lib/game_objects/player_spec.rb +24 -0
  72. data/spec/lib/game_objects/room_spec.rb +20 -0
  73. data/spec/lib/game_objects/thing_spec.rb +7 -0
  74. data/spec/lib/interactions/notify_spec.rb +26 -0
  75. data/spec/lib/interactions/reboot_spec.rb +9 -0
  76. data/spec/lib/ipc/carbon_ipc_socket_spec.rb +12 -0
  77. data/spec/lib/ipc/ipc_message_spec.rb +39 -0
  78. data/spec/lib/ipc/read_socket_spec.bak +51 -0
  79. data/spec/lib/ipc/write_socket_spec.bak +25 -0
  80. data/spec/spec_helper.rb +118 -0
  81. data/spec/support/helpers.rb +15 -0
  82. data/spec/support/matchers/be_boolean.rb +5 -0
  83. data/spec/support/shared_examples/carbon_ipc_socket.rb +3 -0
  84. data/spec/support/shared_examples/container.rb +3 -0
  85. data/spec/support/shared_examples/game_object.rb +6 -0
  86. data/spec/support/shared_examples/movable.rb +4 -0
  87. data/start +5 -0
  88. data/start-server-only +8 -0
  89. metadata +416 -0
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe Connection do
4
+ let(:id) { "foo" }
5
+ let(:connection) { Connection.new(id) }
6
+ let(:message) { "Watson, come here" }
7
+ let(:expected_sent_message) { "Watson, come here\n"}
8
+ let(:player) { double(Player) }
9
+
10
+ context ".id" do
11
+ it "has an ID" do
12
+ expect(connection.id).to eq(id)
13
+ end
14
+
15
+ it "won't let you set the ID" do
16
+ expect { connection.id = id }.to raise_exception(NameError)
17
+ end
18
+ end
19
+
20
+ context ".locale" do
21
+ it "has a locale" do
22
+ expect(connection.locale).to eq("en")
23
+ end
24
+
25
+ it "lets you set the locale" do
26
+ c = Connection.new(id)
27
+ c.locale = "nl"
28
+ expect(c.locale).to eq("nl")
29
+ end
30
+ end
31
+
32
+ context ".write_translated" do
33
+ it "sends .write to CarbonMU.server" do
34
+ expect(I18n).to receive(:t) { message }
35
+ server = stub_carbonmu_server
36
+ expect(server).to receive(:write_to_connection).with(id, expected_sent_message)
37
+ connection.write_translated(message)
38
+ end
39
+ end
40
+
41
+ context ".player" do
42
+ it "is nil for new connections" do
43
+ expect(connection.player).to eq(nil)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,24 @@
1
+ require "spec_helper"
2
+
3
+ describe Internationalization do
4
+
5
+ context ".setup" do
6
+ include FakeFS::SpecHelpers
7
+
8
+ it "loads the right loadpath" do
9
+ FileUtils.mkdir_p("config/locales")
10
+ FileUtils.touch("config/locales/boo.yml")
11
+ CarbonMU::Internationalization.setup
12
+ expect(I18n.load_path).to eq(["/config/locales/boo.yml"])
13
+ end
14
+ end
15
+
16
+ context ".translate" do
17
+ it "calls I18n.t" do
18
+ str = "foo"
19
+ opts = {foo: "bar"}
20
+ expect(I18n).to receive(:t).with(str, [opts])
21
+ CarbonMU::Internationalization.translate(str, opts)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe Parser do
4
+ class ParseTestCommand < Command
5
+ syntax "testing_good_command"
6
+ end
7
+
8
+ let (:connection) { double(Connection).as_null_object }
9
+
10
+ context '.parse_and_execute' do
11
+ it "handles a bad command" do
12
+ expect_any_instance_of(UnknownCommand).to receive(:execute)
13
+
14
+ subject.parse_and_execute(connection, "DEFINITELY_NEVER_GOING_TO_BE_A_GOOD_COMMAND")
15
+ end
16
+
17
+ it "calls .execute on a good command" do
18
+ expect_any_instance_of(ParseTestCommand).to receive(:execute)
19
+ subject.parse_and_execute(connection, "testing_good_command")
20
+ end
21
+ end
22
+
23
+ context '.register_syntax' do
24
+ it "remembers a given syntax and class" do
25
+ class TestEmptyClass; end
26
+ Parser.register_syntax("foo", TestEmptyClass)
27
+ expect(Parser.syntaxes["foo"]).to eq(TestEmptyClass)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe Server do
4
+ context "minimal objects" do
5
+ it "should create the starter Room" do
6
+ r = Room.where(_special: :starting_room).first
7
+ expect(r.class).to eq(Room)
8
+ expect(r.name).to eq("Starting Room")
9
+ expect(r.description).to eq("This is the starting room for newly-created players. Feel free to rename and re-describe it.")
10
+ end
11
+
12
+ it "should create the lost & found Room" do
13
+ r = Room.where(_special: :lostandfound_room).first
14
+ expect(r.class).to eq(Room)
15
+ expect(r.name).to eq("Lost & Found Room")
16
+ expect(r.description).to eq("This is the room where objects and players go if the thing that was holding them gets destroyed.")
17
+ end
18
+
19
+ it "should create the superadmin player" do
20
+ p = Player.where(_special: :superadmin_player).first
21
+ expect(p.class).to eq(Player)
22
+ expect(p.name).to eq("Superadmin")
23
+ expect(p.description).to eq("Obviously the most powerful of his race, it could kill us all.")
24
+ end
25
+ end
26
+
27
+ context "connections" do
28
+ it "temporarily should set new connections to be the super-admin" do #TODO
29
+ s = Server.new(true)
30
+ s.add_connection(1)
31
+ c = s.connections.first
32
+ expect(c.player).to eq(Player.superadmin)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe EdgeConnection do
4
+ it "has a unique id" do
5
+ c1 = EdgeConnection.new
6
+ c2 = EdgeConnection.new
7
+ expect(c1.id).to_not eq(c2)
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ class MyContainer
4
+ include Container
5
+ end
6
+
7
+ describe MyContainer do
8
+ it_behaves_like "a Container"
9
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe Exit do
4
+ it_behaves_like "a GameObject or descendant"
5
+ it_behaves_like "a Movable"
6
+ it { is_expected.to belong_to(:destination).of_type(Exit).as_inverse_of(:incoming_exits).with_index }
7
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe GameObject do
4
+ it_behaves_like "a GameObject or descendant"
5
+
6
+ context ".description" do
7
+ it "has a default description" do
8
+ g = GameObject.new
9
+ expect(g.description).to eq("You see nothing special.")
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ class MyMovable
4
+ include Movable
5
+ end
6
+
7
+ describe MyMovable do
8
+ it_behaves_like "a Movable"
9
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Player do
4
+ it_behaves_like "a GameObject or descendant"
5
+ it_behaves_like "a Movable"
6
+ it_behaves_like "a Container"
7
+
8
+ it "gets a location of the starter room if not otherwise specified" do
9
+ p = Player.create!(location: nil)
10
+ expect(p.location).to eq(Room.starting)
11
+ end
12
+
13
+ it "still can be given a location" do
14
+ r = Room.create!
15
+ p = Player.create!(location: r)
16
+ expect(p.location).to eq(r)
17
+ end
18
+
19
+ context ".superadmin" do
20
+ it "returns the actual superadmin player" do
21
+ expect(Player.superadmin._special).to eq(:superadmin_player)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe Room do
4
+ it_behaves_like "a GameObject or descendant"
5
+ it_behaves_like "a Container"
6
+
7
+ it { is_expected.to have_many(:incoming_exits).of_type(Exit).with_foreign_key(:destination) }
8
+
9
+ context ".starting" do
10
+ it "returns the actual starting room" do
11
+ expect(Room.starting._special).to eq(:starting_room)
12
+ end
13
+ end
14
+
15
+ context ".lostandfound" do
16
+ it "returns the actual lost & found room" do
17
+ expect(Room.lostandfound._special).to eq(:lostandfound_room)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe Thing do
4
+ it_behaves_like "a GameObject or descendant"
5
+ it_behaves_like "a Movable"
6
+ it_behaves_like "a Container"
7
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Notify do
4
+ before(:each) do
5
+ @server = stub_carbonmu_server
6
+ allow(@server).to receive(:connections) { [connection1, connection2] }
7
+ end
8
+
9
+ let(:connection1) { double(Connection) }
10
+ let(:connection2) { double(Connection) }
11
+
12
+ context '.all' do
13
+ it "writes to all connections with the input specified" do
14
+ expect(connection1).to receive(:write_translated).with("foo", {})
15
+ expect(connection2).to receive(:write_translated).with("foo", {})
16
+ Notify.all("foo")
17
+ end
18
+ end
19
+
20
+ context '.one' do
21
+ it "writes to the connection specified with the input" do
22
+ expect(connection1).to receive(:write_translated).with("foo", {})
23
+ Notify.one(connection1, "foo")
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe Reboot do
4
+ it "notifies all of reboot and signals server" do
5
+ expect(Notify).to receive(:all).with(/Rebooting, please wait/)
6
+ expect(Server).to receive(:trigger_reboot)
7
+ Reboot.reboot
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe CarbonIPCSocket do
4
+ it_behaves_like "a CarbonIPCSocket implementation"
5
+
6
+ it "closes a socket if one is defined" do
7
+ sock = CarbonIPCSocket.new
8
+ sock.zmq_socket = double("socket")
9
+ expect(sock.zmq_socket).to receive(:close)
10
+ sock.close
11
+ end
12
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe IPCMessage do
4
+ it "sets its operation properly" do
5
+ ipc = IPCMessage.new(:started)
6
+ expect(ipc.op).to eq(:started)
7
+ end
8
+
9
+ it "supports equality" do
10
+ ipc1 = IPCMessage.new(:write, connection_id: "123", output: "foo")
11
+ ipc2 = IPCMessage.new(:write, connection_id: "123", output: "foo")
12
+ expect(ipc1).to eq(ipc2)
13
+ end
14
+
15
+ it "accepts op parameters" do
16
+ ipc = IPCMessage.new(:write, connection_id: "123", output: "foo")
17
+ expect(ipc.params[:connection_id]).to eq("123")
18
+ expect(ipc.params[:output]).to eq("foo")
19
+ end
20
+
21
+ it "supports direct method access for op parameters" do
22
+ ipc = IPCMessage.new(:write, connection_id: "123", output: "foo")
23
+ expect(ipc.params[:connection_id]).to eq(ipc.connection_id)
24
+ end
25
+
26
+ it "enforces required op parameters" do
27
+ expect { IPCMessage.new(:write, connection_id: '123') }.to raise_error(ArgumentError,/output/)
28
+ end
29
+
30
+ it "raises if given an unknown op" do
31
+ expect { IPCMessage.new(:definitely_not_a_good_op) }.to raise_error(ArgumentError,/definitely_not_a_good_op/)
32
+ end
33
+
34
+ it "knows how to serialize and unserialize itself" do
35
+ original = IPCMessage.new(:write, connection_id: "123", output: "foo")
36
+ round_trip = IPCMessage.unserialize(original.serialize)
37
+ expect(round_trip).to eq(original)
38
+ end
39
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe ReadSocket do
4
+ it_behaves_like "a CarbonIPCSocket implementation"
5
+
6
+ it "raises on send(msg)" do
7
+ expect { ReadSocket.new.send('foo') }.to raise_error(NotImplementedError)
8
+ end
9
+
10
+ it "reads from the underlying socket" do
11
+ sock = ReadSocket.new
12
+ sock.zmq_socket = double("zmq")
13
+ sock.zmq_socket.should_receive(:read)
14
+ sock.read
15
+ end
16
+
17
+ it "attempts to BIND to tcp://127.0.0.1:<specified port>" do
18
+ port_number = rand(10000..20000)
19
+ zmqsocket = double("zmqsocket")
20
+ zmqsocket.stub(:connect).with(anything)
21
+ zmqsocket.should_receive(:bind).with("tcp://127.0.0.1:#{port_number}")
22
+ Celluloid::ZMQ::PullSocket.stub(:new) { zmqsocket }
23
+ ReadSocket.new(port_number)
24
+ end
25
+
26
+ it "knows its own port number" do
27
+ port_number = rand(10000..20000)
28
+ r = ReadSocket.new(port_number)
29
+ r.port_number.should eq(port_number)
30
+ end
31
+
32
+ context "ephemeral ports" do
33
+ it "supports binding to an ephemeral port" do
34
+ zmqsocket = double("zmqsocket")
35
+ zmqsocket.stub(:bind).with(anything)
36
+ zmqsocket.should_receive(:bind).with("tcp://127.0.0.1:*")
37
+ Celluloid::ZMQ::PullSocket.stub(:new) { zmqsocket }
38
+ ReadSocket.new
39
+ end
40
+
41
+ it "returns a valid port number when bound to an ephemeral port" do
42
+ ReadSocket.new.port_number.should be_between(1024,65535)
43
+ end
44
+
45
+ it "returns a different port number on successive instantiations" do
46
+ r1 = ReadSocket.new
47
+ r2 = ReadSocket.new
48
+ r1.port_number.should_not eq(r2.port_number)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe WriteSocket do
4
+ it_behaves_like "a CarbonIPCSocket implementation"
5
+
6
+ it "raises on read" do
7
+ expect { WriteSocket.new.read }.to raise_error(NotImplementedError)
8
+ end
9
+
10
+ it "writes to the underlying socket" do
11
+ sock = WriteSocket.new
12
+ sock.zmq_socket = double("zmq")
13
+ expect(sock.zmq_socket).to receive(:send).with("foo")
14
+ sock.send("foo")
15
+ end
16
+
17
+ it "attempts to CONNECT to tcp://127.0.0.1:<specified port>" do
18
+ port_number = rand(10000..20000)
19
+ zmqsocket = double("zmqsocket")
20
+ allow(zmqsocket).to receive(:bind)
21
+ expect(zmqsocket).to receive(:connect).with("tcp://127.0.0.1:#{port_number}")
22
+ allow(Celluloid::ZMQ::PushSocket).to receive(:new) { zmqsocket }
23
+ WriteSocket.new(port_number)
24
+ end
25
+ end
@@ -0,0 +1,118 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
4
+ # this file to always be loaded, without a need to explicitly require it in any
5
+ # files.
6
+ #
7
+ # Given that it is always loaded, you are encouraged to keep this file as
8
+ # light-weight as possible. Requiring heavyweight dependencies from this file
9
+ # will add to the boot time of your test suite on EVERY test run, even for an
10
+ # individual file that may not need all of that loaded. Instead, consider making
11
+ # a separate helper file that requires the additional dependencies and performs
12
+ # the additional setup, and require it from the spec files that actually need
13
+ # it.
14
+ #
15
+ # The `.rspec` file also contains a few flags that are not defaults but that
16
+ # users commonly want.
17
+
18
+ ENV['MONGOID_ENV'] = "testing"
19
+
20
+ require 'bundler'
21
+ require 'timecop'
22
+ require_relative '../lib/carbonmu.rb'
23
+ require 'pry'
24
+ require 'mongoid-rspec'
25
+ require 'database_cleaner'
26
+ require 'fakefs/spec_helpers'
27
+
28
+ Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f}
29
+
30
+ include CarbonMU
31
+ CarbonMU.configure do |c|
32
+ c.logger = Logger.new(nil)
33
+ end
34
+
35
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
36
+ RSpec.configure do |config|
37
+ config.filter_run_excluding :i18n => true
38
+ config.raise_errors_for_deprecations!
39
+ config.include Helpers
40
+ config.include Mongoid::Matchers
41
+
42
+ config.before(:suite) do
43
+ Server.initialize_database
44
+ DatabaseCleaner.strategy = :truncation
45
+ DatabaseCleaner.clean
46
+ end
47
+
48
+ config.around(:each) do |example|
49
+ DatabaseCleaner.cleaning do
50
+ Server.create_starter_objects
51
+ example.run
52
+ end
53
+ end
54
+
55
+
56
+ # rspec-expectations config goes here. You can use an alternate
57
+ # assertion/expectation library such as wrong or the stdlib/minitest
58
+ # assertions if you prefer.
59
+ config.expect_with :rspec do |expectations|
60
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
61
+ end
62
+
63
+ # rspec-mocks config goes here. You can use an alternate test double
64
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
65
+ config.mock_with :rspec do |mocks|
66
+ # Prevents you from mocking or stubbing a method that does not exist on
67
+ # a real object. This is generally recommended, and will default to
68
+ # `true` in RSpec 4.
69
+ mocks.verify_partial_doubles = true
70
+ end
71
+
72
+ # The settings below are suggested to provide a good initial experience
73
+ # with RSpec, but feel free to customize to your heart's content.
74
+ # These two settings work together to allow you to limit a spec run
75
+ # to individual examples or groups you care about by tagging them with
76
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
77
+ # get run.
78
+ config.filter_run :focus
79
+ config.run_all_when_everything_filtered = true
80
+
81
+ # Limits the available syntax to the non-monkey patched syntax that is
82
+ # recommended. For more details, see:
83
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
84
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
85
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
86
+ # config.disable_monkey_patching!
87
+
88
+ # This setting enables warnings. It's recommended, but in some cases may
89
+ # be too noisy due to issues in dependencies.
90
+ config.warnings = false
91
+
92
+ # Many RSpec users commonly either run the entire suite or an individual
93
+ # file, and it's useful to allow more verbose output when running an
94
+ # individual spec file.
95
+ if config.files_to_run.one?
96
+ # Use the documentation formatter for detailed output,
97
+ # unless a formatter has already been configured
98
+ # (e.g. via a command-line flag).
99
+ config.default_formatter = 'doc'
100
+ end
101
+
102
+ # Print the 10 slowest examples and example groups at the
103
+ # end of the spec run, to help surface which specs are running
104
+ # particularly slow.
105
+ # config.profile_examples = 10
106
+
107
+ # Run specs in random order to surface order dependencies. If you find an
108
+ # order dependency and want to debug it, you can fix the order by providing
109
+ # the seed, which is printed after each run.
110
+ # --seed 1234
111
+ config.order = :random
112
+
113
+ # Seed global randomization in this process using the `--seed` CLI option.
114
+ # Setting this allows you to use `--seed` to deterministically reproduce
115
+ # test failures related to randomization by passing the same `--seed` value
116
+ # as the one that triggered the failure.
117
+ Kernel.srand config.seed
118
+ end