lita 3.3.1 → 4.0.0.rc1

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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/.travis.yml +3 -0
  4. data/lib/lita.rb +45 -97
  5. data/lib/lita/adapter.rb +38 -17
  6. data/lib/lita/adapters/shell.rb +5 -3
  7. data/lib/lita/authorization.rb +109 -60
  8. data/lib/lita/builder.rb +38 -0
  9. data/lib/lita/callback.rb +37 -0
  10. data/lib/lita/cli.rb +2 -0
  11. data/lib/lita/config.rb +1 -18
  12. data/lib/lita/configurable.rb +29 -0
  13. data/lib/lita/configuration.rb +179 -0
  14. data/lib/lita/configuration_validator.rb +66 -0
  15. data/lib/lita/daemon.rb +4 -11
  16. data/lib/lita/default_configuration.rb +146 -0
  17. data/lib/lita/errors.rb +9 -0
  18. data/lib/lita/handler.rb +5 -264
  19. data/lib/lita/handler/chat_router.rb +130 -0
  20. data/lib/lita/handler/common.rb +114 -0
  21. data/lib/lita/handler/event_router.rb +77 -0
  22. data/lib/lita/handler/http_router.rb +26 -0
  23. data/lib/lita/handlers/authorization.rb +13 -18
  24. data/lib/lita/handlers/deprecation_check.rb +24 -0
  25. data/lib/lita/handlers/help.rb +5 -3
  26. data/lib/lita/handlers/info.rb +2 -2
  27. data/lib/lita/http_callback.rb +29 -0
  28. data/lib/lita/http_route.rb +41 -26
  29. data/lib/lita/namespace.rb +23 -0
  30. data/lib/lita/rack_app.rb +29 -2
  31. data/lib/lita/registry.rb +133 -0
  32. data/lib/lita/robot.rb +58 -20
  33. data/lib/lita/route_validator.rb +12 -4
  34. data/lib/lita/rspec.rb +23 -14
  35. data/lib/lita/rspec/handler.rb +93 -23
  36. data/lib/lita/rspec/matchers/chat_route_matcher.rb +48 -0
  37. data/lib/lita/rspec/matchers/deprecated.rb +36 -0
  38. data/lib/lita/rspec/matchers/event_route_matcher.rb +27 -0
  39. data/lib/lita/rspec/matchers/http_route_matcher.rb +18 -60
  40. data/lib/lita/user.rb +0 -6
  41. data/lib/lita/util.rb +1 -8
  42. data/lib/lita/version.rb +1 -1
  43. data/lita.gemspec +1 -0
  44. data/spec/lita/adapter_spec.rb +25 -7
  45. data/spec/lita/adapters/shell_spec.rb +24 -4
  46. data/spec/lita/authorization_spec.rb +57 -38
  47. data/spec/lita/builder_spec.rb +39 -0
  48. data/spec/lita/config_spec.rb +0 -24
  49. data/spec/lita/configuration_spec.rb +222 -0
  50. data/spec/lita/configuration_validator_spec.rb +112 -0
  51. data/spec/lita/daemon_spec.rb +2 -2
  52. data/spec/lita/default_configuration_spec.rb +254 -0
  53. data/spec/lita/handler/chat_router_spec.rb +192 -0
  54. data/spec/lita/handler/common_spec.rb +272 -0
  55. data/spec/lita/handler/event_router_spec.rb +54 -0
  56. data/spec/lita/handler/http_router_spec.rb +106 -0
  57. data/spec/lita/handler_spec.rb +20 -291
  58. data/spec/lita/handlers/authorization_spec.rb +9 -11
  59. data/spec/lita/handlers/deprecation_check_spec.rb +21 -0
  60. data/spec/lita/handlers/help_spec.rb +31 -9
  61. data/spec/lita/handlers/info_spec.rb +2 -2
  62. data/spec/lita/handlers/room_spec.rb +5 -3
  63. data/spec/lita/robot_spec.rb +30 -11
  64. data/spec/lita/rspec_spec.rb +71 -31
  65. data/spec/lita/user_spec.rb +2 -2
  66. data/spec/lita_spec.rb +62 -4
  67. data/spec/spec_helper.rb +7 -0
  68. data/templates/locales/en.yml +56 -4
  69. data/templates/plugin/gemspec.tt +1 -0
  70. data/templates/plugin/spec/spec_helper.tt +4 -0
  71. metadata +54 -8
  72. data/lib/lita/rspec/matchers/event_subscription_matcher.rb +0 -67
  73. data/lib/lita/rspec/matchers/route_matcher.rb +0 -69
  74. data/spec/lita/rack_app_spec.rb +0 -92
@@ -2,19 +2,17 @@ require "spec_helper"
2
2
 
3
3
  describe Lita::Handlers::Authorization, lita_handler: true do
4
4
  before do
5
- allow(Lita::Authorization).to receive(:user_is_admin?).with(
6
- user
7
- ).and_return(true)
5
+ allow(robot.auth).to receive(:user_is_admin?).with(user).and_return(true)
8
6
  end
9
7
 
10
8
  let(:target_user) { instance_double("Lita::User", id: "1", name: "Carl") }
11
9
 
12
- it { routes_command("auth add foo bar").to(:add) }
13
- it { routes_command("auth add foo@bar.com baz").to(:add) }
14
- it { routes_command("auth remove foo bar").to(:remove) }
15
- it { routes_command("auth remove foo@bar.com baz").to(:remove) }
16
- it { routes_command("auth list").to(:list) }
17
- it { routes_command("auth list foo").to(:list) }
10
+ it { is_expected.to route_command("auth add foo bar").to(:add) }
11
+ it { is_expected.to route_command("auth add foo@bar.com baz").to(:add) }
12
+ it { is_expected.to route_command("auth remove foo bar").to(:remove) }
13
+ it { is_expected.to route_command("auth remove foo@bar.com baz").to(:remove) }
14
+ it { is_expected.to route_command("auth list").to(:list) }
15
+ it { is_expected.to route_command("auth list foo").to(:list) }
18
16
 
19
17
  describe "#add" do
20
18
  it "replies with the proper format if the require commands are missing" do
@@ -77,8 +75,8 @@ describe Lita::Handlers::Authorization, lita_handler: true do
77
75
 
78
76
  before do
79
77
  groups.each do |group|
80
- Lita::Authorization.add_user_to_group(user, user1, group)
81
- Lita::Authorization.add_user_to_group(user, user2, group)
78
+ subject.robot.auth.add_user_to_group(user, user1, group)
79
+ subject.robot.auth.add_user_to_group(user, user2, group)
82
80
  end
83
81
  end
84
82
 
@@ -0,0 +1,21 @@
1
+ require "spec_helper"
2
+
3
+ describe Lita::Handlers::DeprecationCheck, lita_handler: true do
4
+ it { is_expected.to route_event(:loaded).to(:check_handlers_for_default_config) }
5
+
6
+ describe "#check_handlers_for_default_config" do
7
+ before do
8
+ registry.register_handler(:foo) do
9
+ def self.default_config(old_config)
10
+ old_config.bar = :baz
11
+ end
12
+ end
13
+ end
14
+
15
+ it "logs a warning for handlers using the default_config method" do
16
+ expect(Lita.logger).to receive(:warn).with(/found defined in the foo handler/)
17
+
18
+ robot.trigger(:loaded, {})
19
+ end
20
+ end
21
+ end
@@ -1,8 +1,8 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe Lita::Handlers::Help, lita_handler: true do
4
- it { routes_command("help").to(:help) }
5
- it { routes_command("help foo").to(:help) }
4
+ it { is_expected.to route_command("help").to(:help) }
5
+ it { is_expected.to route_command("help foo").to(:help) }
6
6
 
7
7
  describe "#help" do
8
8
  let(:secret_handler_class) do
@@ -12,6 +12,7 @@ describe Lita::Handlers::Help, lita_handler: true do
12
12
  })
13
13
  end
14
14
  end
15
+
15
16
  it "sends help information for all commands" do
16
17
  send_command("help")
17
18
  expect(replies.last).to match(
@@ -25,13 +26,34 @@ describe Lita::Handlers::Help, lita_handler: true do
25
26
  expect(replies.last).not_to match(/help - Lists/)
26
27
  end
27
28
 
28
- it "doesn't show help for commands the user doesn't have access to" do
29
- allow(Lita).to receive(:handlers).and_return([
30
- described_class,
31
- secret_handler_class
32
- ])
33
- send_command("help")
34
- expect(replies.last).not_to include("secret")
29
+ it "doesn't crash if a handler doesn't have routes" do
30
+ event_handler = Class.new do
31
+ extend Lita::Handler::EventRouter
32
+ end
33
+
34
+ registry.register_handler(event_handler)
35
+
36
+ expect { send_command("help") }.not_to raise_error
37
+ end
38
+
39
+ describe "restricted routes" do
40
+ let(:authorized_user) do
41
+ user = Lita::User.create(2, name: "Authorized User")
42
+ Lita::Authorization.new(robot).add_user_to_group!(user, :the_nobodies)
43
+ user
44
+ end
45
+
46
+ before { registry.register_handler(secret_handler_class) }
47
+
48
+ it "doesn't show help for commands the user doesn't have access to" do
49
+ send_command("help")
50
+ expect(replies.last).not_to include("secret")
51
+ end
52
+
53
+ it "shows help for restricted routes if the user has access" do
54
+ send_command("help", as: authorized_user)
55
+ expect(replies.last).to include("secret")
56
+ end
35
57
  end
36
58
  end
37
59
  end
@@ -1,8 +1,8 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe Lita::Handlers::Info, lita_handler: true do
4
- it { routes_command("info").to(:chat) }
5
- it { routes_http(:get, "/lita/info").to(:web) }
4
+ it { is_expected.to route_command("info").to(:chat) }
5
+ it { is_expected.to route_http(:get, "/lita/info").to(:web) }
6
6
 
7
7
  let(:request) { double("Rack::Request") }
8
8
  let(:response) { Rack::Response.new }
@@ -1,8 +1,10 @@
1
+ require "spec_helper"
2
+
1
3
  describe Lita::Handlers::Room, lita_handler: true do
2
- it { routes_command("join #lita.io").to(:join) }
3
- it { routes_command("part #lita.io").to(:part) }
4
+ it { is_expected.to route_command("join #lita.io").to(:join) }
5
+ it { is_expected.to route_command("part #lita.io").to(:part) }
4
6
 
5
- before { allow(Lita::Authorization).to receive(:user_is_admin?).with(user).and_return(true) }
7
+ before { allow(robot.auth).to receive(:user_is_admin?).with(user).and_return(true) }
6
8
 
7
9
  describe "#join" do
8
10
  it "calls Robot#join with the provided ID" do
@@ -1,13 +1,9 @@
1
1
  require "spec_helper"
2
2
 
3
- describe Lita::Robot do
4
- it "logs and quits if the specified adapter can't be found" do
5
- adapter_registry = double("adapter_registry")
6
- allow(Lita).to receive(:adapters).and_return(adapter_registry)
7
- allow(adapter_registry).to receive(:[]).and_return(nil)
8
- expect(Lita.logger).to receive(:fatal).with(/Unknown adapter/)
9
- expect { subject }.to raise_error(SystemExit)
10
- end
3
+ describe Lita::Robot, lita: true do
4
+ subject { described_class.new(registry) }
5
+
6
+ before { registry.register_adapter(:shell, Lita::Adapters::Shell) }
11
7
 
12
8
  it "triggers a loaded event after initialization" do
13
9
  expect_any_instance_of(described_class).to receive(:trigger).with(:loaded)
@@ -15,11 +11,12 @@ describe Lita::Robot do
15
11
  end
16
12
 
17
13
  context "with registered handlers" do
18
- let(:handler1) { class_double("Lita::Handler", http_routes: [], trigger: nil) }
19
- let(:handler2) { class_double("Lita::Handler", http_routes: [], trigger: nil) }
14
+ let(:handler1) { Class.new(Lita::Handler) { namespace :test } }
15
+ let(:handler2) { Class.new(Lita::Handler) { namespace :test } }
20
16
 
21
17
  before do
22
- allow(Lita).to receive(:handlers).and_return([handler1, handler2])
18
+ registry.register_handler(handler1)
19
+ registry.register_handler(handler2)
23
20
  end
24
21
 
25
22
  describe "#receive" do
@@ -70,6 +67,26 @@ describe Lita::Robot do
70
67
  expect_any_instance_of(Lita::Adapters::Shell).to receive(:shut_down)
71
68
  subject.run
72
69
  end
70
+
71
+ it "logs and quits if the specified adapter can't be found" do
72
+ registry.config.robot.adapter = :does_not_exist
73
+ expect(Lita.logger).to receive(:fatal).with(/Unknown adapter/)
74
+ expect { subject.run }.to raise_error(SystemExit)
75
+ end
76
+
77
+ it "logs and aborts if the web server's port is in use" do
78
+ allow_any_instance_of(Puma::Server).to receive(:add_tcp_listener).and_raise(Errno::EADDRINUSE)
79
+
80
+ expect(Lita.logger).to receive(:fatal).with(/web server/)
81
+ expect { subject.run }.to raise_error(SystemExit)
82
+ end
83
+
84
+ it "logs and aborts if the web server's port is privileged" do
85
+ allow_any_instance_of(Puma::Server).to receive(:add_tcp_listener).and_raise(Errno::EACCES)
86
+
87
+ expect(Lita.logger).to receive(:fatal).with(/web server/)
88
+ expect { subject.run }.to raise_error(SystemExit)
89
+ end
73
90
  end
74
91
 
75
92
  describe "#join" do
@@ -151,6 +168,8 @@ describe Lita::Robot do
151
168
  end
152
169
 
153
170
  describe "#shut_down" do
171
+ before { allow_any_instance_of(Lita::Adapters::Shell).to receive(:puts) }
172
+
154
173
  it "gracefully stops the adapter" do
155
174
  expect_any_instance_of(Lita::Adapters::Shell).to receive(:shut_down)
156
175
  subject.shut_down
@@ -1,20 +1,21 @@
1
1
  require "spec_helper"
2
2
 
3
3
  handler_class = Class.new(Lita::Handler) do
4
- route(/^\w{3}$/, :foo)
5
- route(/^\w{4}$/, :blah, command: true)
4
+ route(/^message$/, :message)
5
+ route(/^command$/, :command, command: true)
6
6
  route("restricted", :restricted, restrict_to: :some_group)
7
+ route("admins only", :admins_only, restrict_to: :admins)
7
8
 
8
9
  http.get "web", :web
9
10
 
10
11
  on :connected, :greet
11
12
 
12
- def foo(response)
13
- response.reply "baz"
13
+ def message(response)
14
+ response.reply(response.user.name)
14
15
  end
15
16
 
16
- def blah(response)
17
- response.reply "bongo", "wongo"
17
+ def command(response)
18
+ response.reply("a", "command")
18
19
  end
19
20
 
20
21
  def restricted(_response)
@@ -32,38 +33,77 @@ handler_class = Class.new(Lita::Handler) do
32
33
  end
33
34
 
34
35
  describe handler_class, lita_handler: true do
35
- it { routes("foo").to(:foo) }
36
- it { routes_command("blah").to(:blah) }
37
- it { doesnt_route("blah").to(:blah) }
38
- it { does_not_route("blah").to(:blah) }
39
- it { doesnt_route_command("yo").to(:foo) }
40
- it { does_not_route_command("yo").to(:foo) }
41
- it { routes("restricted").to(:restricted) }
42
- it { routes_http(:get, "web").to(:web) }
43
- it { doesnt_route_http(:post, "web").to(:web) }
44
- it { routes_event(:connected).to(:greet) }
45
- it { doesnt_route_event(:connected).to(:web) }
46
- it { does_not_route_event(:connected).to(:web) }
47
-
48
- describe "#foo" do
49
- it "replies with baz" do
50
- send_message("foo")
51
- expect(replies).to eq(["baz"])
36
+ describe "routing messages" do
37
+ it { is_expected.to route("message") }
38
+ it { is_expected.to route("message").to(:message) }
39
+ it { is_expected.not_to route("message").to(:not_a_message) }
40
+ end
41
+
42
+ describe "routing commands" do
43
+ it { is_expected.to route_command("command") }
44
+ it { is_expected.not_to route("command") }
45
+ it { is_expected.not_to route_command("not a command") }
46
+ it { is_expected.to route_command("command").to(:command) }
47
+ it { is_expected.not_to route_command("command").to(:not_a_command) }
48
+ end
49
+
50
+ describe "routing to restricted routes" do
51
+ it { is_expected.not_to route("restricted") }
52
+ it { is_expected.to route("restricted").with_authorization_for(:some_group) }
53
+ it { is_expected.not_to route("restricted").with_authorization_for(:wrong_group) }
54
+ it { is_expected.to route("admins only").with_authorization_for(:admins) }
55
+ it { is_expected.to route("restricted").with_authorization_for(:some_group).to(:restricted) }
56
+ it { is_expected.not_to route("restricted").with_authorization_for(:some_group).to(:nothing) }
57
+ end
58
+
59
+ describe "routing HTTP routes" do
60
+ it { is_expected.to route_http(:get, "web") }
61
+ it { is_expected.to route_http(:get, "web").to(:web) }
62
+ it { is_expected.not_to route_http(:get, "web").to(:message) }
63
+ it { is_expected.not_to route_http(:post, "web") }
64
+ end
65
+
66
+ describe "routing events" do
67
+ it { is_expected.to route_event(:connected) }
68
+ it { is_expected.to route_event(:connected).to(:greet) }
69
+ it { is_expected.not_to route_event(:not_an_event) }
70
+ it { is_expected.not_to route_event(:connected).to(:message) }
71
+ end
72
+
73
+ describe "deprecated routing syntax" do
74
+ before { allow(STDERR).to receive(:puts) }
75
+
76
+ it { routes("message").to(:message) }
77
+ it { routes_command("command").to(:command) }
78
+ it { doesnt_route("command").to(:command) }
79
+ it { does_not_route("command").to(:command) }
80
+ it { doesnt_route_command("not a command").to(:message) }
81
+ it { does_not_route_command("not a command").to(:message) }
82
+ it { routes("restricted").to(:restricted) }
83
+ it { routes_http(:get, "web").to(:web) }
84
+ it { doesnt_route_http(:post, "web").to(:web) }
85
+ it { routes_event(:connected).to(:greet) }
86
+ it { doesnt_route_event(:connected).to(:web) }
87
+ it { does_not_route_event(:connected).to(:web) }
88
+ end
89
+
90
+ describe "#message" do
91
+ it "replies with a string" do
92
+ send_message("message")
93
+ expect(replies).to eq(["Test User"])
52
94
  end
53
95
  end
54
96
 
55
- describe "#blah" do
56
- it "replies with bongo and wongo" do
57
- send_command("blah")
58
- expect(replies).to eq(%w(bongo wongo))
97
+ describe "#command" do
98
+ it "replies with two strings" do
99
+ send_command("command")
100
+ expect(replies).to eq(%w(a command))
59
101
  end
60
102
  end
61
103
 
62
104
  it "allows the sending user to be specified" do
63
105
  another_user = Lita::User.create(2, name: "Another User")
64
- expect(robot).to receive(:receive) do |message|
65
- expect(message.source.user).to eq(another_user)
66
- end
67
- send_message("foo", as: another_user)
106
+ send_message("message", as: another_user)
107
+ expect(replies.last).to eq("Another User")
68
108
  end
69
109
  end
@@ -6,13 +6,13 @@ describe Lita::User, lita: true do
6
6
  user = described_class.create(1, name: "Carl")
7
7
  expect(user.id).to eq("1")
8
8
  expect(user.name).to eq("Carl")
9
- persisted_user = described_class.find(1)
9
+ persisted_user = described_class.find_by_id(1)
10
10
  expect(user).to eq(persisted_user)
11
11
  end
12
12
 
13
13
  it "returns existing users" do
14
14
  described_class.create(1, name: "Carl")
15
- user = described_class.find(1)
15
+ user = described_class.find_by_id(1)
16
16
  expect(user.id).to eq("1")
17
17
  expect(user.name).to eq("Carl")
18
18
  end
@@ -4,7 +4,6 @@ describe Lita do
4
4
  before { described_class.register_adapter(:shell, Lita::Adapters::Shell) }
5
5
 
6
6
  it "memoizes a Config" do
7
- expect(described_class.config).to be_a(Lita::Config)
8
7
  expect(described_class.config).to eql(described_class.config)
9
8
  end
10
9
 
@@ -60,10 +59,57 @@ describe Lita do
60
59
  end
61
60
 
62
61
  describe ".redis" do
62
+ let(:redis_namespace) { instance_double("Redis") }
63
+
64
+ before do
65
+ if described_class.instance_variable_defined?(:@redis)
66
+ described_class.remove_instance_variable(:@redis)
67
+ end
68
+
69
+ allow(redis_namespace).to receive(:ping).and_return("PONG")
70
+ allow(Redis::Namespace).to receive(:new).and_return(redis_namespace)
71
+ end
72
+
63
73
  it "memoizes a Redis::Namespace" do
64
- expect(described_class.redis).to respond_to(:namespace)
74
+ expect(described_class.redis).to equal(redis_namespace)
65
75
  expect(described_class.redis).to eql(described_class.redis)
66
76
  end
77
+
78
+ it "logs a fatal warning and raises an exception if it can't connection to Redis" do
79
+ allow(redis_namespace).to receive(:ping).and_raise(Redis::CannotConnectError)
80
+
81
+ expect(Lita.logger).to receive(:fatal)
82
+ expect { Lita.redis }.to raise_error(SystemExit)
83
+ end
84
+ end
85
+
86
+ describe ".register_adapter" do
87
+ let(:robot) { instance_double("Lita::Robot") }
88
+
89
+ it "builds an adapter out of a provided block" do
90
+ described_class.register_adapter(:foo) {}
91
+ expect(Lita.logger).to receive(:warn).with(/not implemented/)
92
+ Lita.adapters[:foo].new(robot).run
93
+ end
94
+
95
+ it "raises if a non-class object is passed as the adapter" do
96
+ expect do
97
+ described_class.register_adapter(:foo, :bar)
98
+ end.to raise_error(ArgumentError, /requires a class/)
99
+ end
100
+ end
101
+
102
+ describe ".register_handler" do
103
+ it "builds a handler out of a provided block" do
104
+ described_class.register_handler(:foo) {}
105
+ expect(described_class.handlers.to_a.last.namespace).to eq("foo")
106
+ end
107
+
108
+ it "raises if a non-class object is the only argument" do
109
+ expect do
110
+ described_class.register_handler(:foo)
111
+ end.to raise_error(ArgumentError, /requires a class/)
112
+ end
67
113
  end
68
114
 
69
115
  describe ".reset" do
@@ -74,13 +120,13 @@ describe Lita do
74
120
  end
75
121
 
76
122
  it "clears adapters" do
77
- described_class.register_adapter(:foo, double)
123
+ described_class.register_adapter(:foo, Class.new)
78
124
  described_class.reset
79
125
  expect(described_class.adapters).to be_empty
80
126
  end
81
127
 
82
128
  it "clears handlers" do
83
- described_class.register_handler(double)
129
+ described_class.register_handler(Class.new)
84
130
  described_class.reset
85
131
  expect(described_class.handlers).to be_empty
86
132
  end
@@ -94,11 +140,17 @@ describe Lita do
94
140
 
95
141
  describe ".run" do
96
142
  let(:hook) { double("Hook") }
143
+ let(:validator) { instance_double("Lita::ConfigurationValidator", call: nil) }
97
144
 
98
145
  before do
99
146
  allow_any_instance_of(Lita::Robot).to receive(:run)
147
+ allow(Lita::ConfigurationValidator).to receive(:new).with(described_class).and_return(
148
+ validator
149
+ )
100
150
  end
101
151
 
152
+ after { described_class.reset }
153
+
102
154
  it "runs a new Robot" do
103
155
  expect_any_instance_of(Lita::Robot).to receive(:run)
104
156
  described_class.run
@@ -109,5 +161,11 @@ describe Lita do
109
161
  expect(hook).to receive(:call).with(config_path: "path/to/config")
110
162
  described_class.run("path/to/config")
111
163
  end
164
+
165
+ it "raises if the configuration is not valid" do
166
+ allow(validator).to receive(:call).and_raise(Lita::ValidationError)
167
+
168
+ expect { described_class.run }.to raise_error(Lita::ValidationError)
169
+ end
112
170
  end
113
171
  end