lita 3.3.1 → 4.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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