flapjack 0.7.35 → 0.8.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.
Files changed (114) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -1
  3. data/Gemfile +3 -4
  4. data/Guardfile +1 -1
  5. data/README.md +38 -19
  6. data/Rakefile +1 -3
  7. data/etc/flapjack_config.yaml.example +11 -1
  8. data/features/steps/cli_steps.rb +3 -3
  9. data/features/steps/events_steps.rb +7 -6
  10. data/features/steps/flapjack-netsaint-parser_steps.rb +8 -8
  11. data/features/steps/notifications_steps.rb +10 -10
  12. data/features/steps/packaging-lintian_steps.rb +5 -9
  13. data/features/steps/time_travel_steps.rb +1 -1
  14. data/flapjack.gemspec +4 -3
  15. data/lib/flapjack/data/contact.rb +78 -6
  16. data/lib/flapjack/data/entity.rb +11 -2
  17. data/lib/flapjack/data/notification_rule.rb +67 -59
  18. data/lib/flapjack/data/semaphore.rb +44 -0
  19. data/lib/flapjack/gateways/api.rb +24 -28
  20. data/lib/flapjack/gateways/api/contact_methods.rb +1 -2
  21. data/lib/flapjack/gateways/api/entity_methods.rb +3 -3
  22. data/lib/flapjack/gateways/jsonapi.rb +249 -0
  23. data/lib/flapjack/gateways/jsonapi/contact_methods.rb +544 -0
  24. data/lib/flapjack/gateways/jsonapi/entity_check_presenter.rb +217 -0
  25. data/lib/flapjack/gateways/jsonapi/entity_methods.rb +350 -0
  26. data/lib/flapjack/gateways/jsonapi/entity_presenter.rb +75 -0
  27. data/lib/flapjack/gateways/jsonapi/rack/json_params_parser.rb +32 -0
  28. data/lib/flapjack/gateways/web.rb +78 -12
  29. data/lib/flapjack/gateways/web/public/css/bootstrap-theme.css +397 -0
  30. data/lib/flapjack/gateways/web/public/css/bootstrap-theme.min.css +7 -0
  31. data/lib/flapjack/gateways/web/public/css/bootstrap.css +7118 -0
  32. data/lib/flapjack/gateways/web/public/css/bootstrap.min.css +6 -8
  33. data/lib/flapjack/gateways/web/public/css/font-awesome.css +1338 -0
  34. data/lib/flapjack/gateways/web/public/css/font-awesome.min.css +4 -0
  35. data/lib/flapjack/gateways/web/public/css/screen.css +80 -0
  36. data/lib/flapjack/gateways/web/public/css/select2-bootstrap.css +87 -0
  37. data/lib/flapjack/gateways/web/public/css/select2.css +615 -0
  38. data/lib/flapjack/gateways/web/public/fonts/FontAwesome.otf +0 -0
  39. data/lib/flapjack/gateways/web/public/fonts/fontawesome-webfont.eot +0 -0
  40. data/lib/flapjack/gateways/web/public/fonts/fontawesome-webfont.svg +414 -0
  41. data/lib/flapjack/gateways/web/public/fonts/fontawesome-webfont.ttf +0 -0
  42. data/lib/flapjack/gateways/web/public/fonts/fontawesome-webfont.woff +0 -0
  43. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.eot +0 -0
  44. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.svg +229 -0
  45. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.ttf +0 -0
  46. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.woff +0 -0
  47. data/lib/flapjack/gateways/web/public/img/flapjack-2013-notext-transparent-300-300.png +0 -0
  48. data/lib/flapjack/gateways/web/public/img/select2.png +0 -0
  49. data/lib/flapjack/gateways/web/public/img/select2x2.png +0 -0
  50. data/lib/flapjack/gateways/web/public/js/backbone-min.js +2 -0
  51. data/lib/flapjack/gateways/web/public/js/backbone.js +1581 -0
  52. data/lib/flapjack/gateways/web/public/js/backbone.jsonapi.js +75 -0
  53. data/lib/flapjack/gateways/web/public/js/bootstrap.js +2276 -0
  54. data/lib/flapjack/gateways/web/public/js/contacts.js +225 -0
  55. data/lib/flapjack/gateways/web/public/js/jquery-1.10.2.js +9789 -0
  56. data/lib/flapjack/gateways/web/public/js/jquery-1.10.2.min.js +6 -0
  57. data/lib/flapjack/gateways/web/public/js/select2.js +3255 -0
  58. data/lib/flapjack/gateways/web/public/js/select2.min.js +22 -0
  59. data/lib/flapjack/gateways/web/public/js/underscore-min.js +6 -0
  60. data/lib/flapjack/gateways/web/public/js/underscore.js +1276 -0
  61. data/lib/flapjack/gateways/web/views/check.html.erb +423 -193
  62. data/lib/flapjack/gateways/web/views/checks.html.erb +51 -71
  63. data/lib/flapjack/gateways/web/views/contact.html.erb +142 -164
  64. data/lib/flapjack/gateways/web/views/contacts.html.erb +20 -40
  65. data/lib/flapjack/gateways/web/views/edit_contacts.html.erb +83 -0
  66. data/lib/flapjack/gateways/web/views/entities.html.erb +18 -37
  67. data/lib/flapjack/gateways/web/views/entity.html.erb +46 -65
  68. data/lib/flapjack/gateways/web/views/index.html.erb +6 -27
  69. data/lib/flapjack/gateways/web/views/layout.erb +95 -0
  70. data/lib/flapjack/gateways/web/views/self_stats.html.erb +100 -114
  71. data/lib/flapjack/pikelet.rb +4 -2
  72. data/lib/flapjack/version.rb +1 -1
  73. data/spec/lib/flapjack/coordinator_spec.rb +120 -120
  74. data/spec/lib/flapjack/data/contact_spec.rb +66 -58
  75. data/spec/lib/flapjack/data/entity_check_spec.rb +179 -179
  76. data/spec/lib/flapjack/data/entity_spec.rb +71 -71
  77. data/spec/lib/flapjack/data/event_spec.rb +34 -30
  78. data/spec/lib/flapjack/data/message_spec.rb +6 -6
  79. data/spec/lib/flapjack/data/notification_rule_spec.rb +24 -24
  80. data/spec/lib/flapjack/data/notification_spec.rb +19 -19
  81. data/spec/lib/flapjack/data/semaphore_spec.rb +24 -0
  82. data/spec/lib/flapjack/data/tag_spec.rb +11 -10
  83. data/spec/lib/flapjack/gateways/api/contact_methods_spec.rb +201 -201
  84. data/spec/lib/flapjack/gateways/api/entity_check_presenter_spec.rb +55 -55
  85. data/spec/lib/flapjack/gateways/api/entity_methods_spec.rb +257 -257
  86. data/spec/lib/flapjack/gateways/api/entity_presenter_spec.rb +26 -26
  87. data/spec/lib/flapjack/gateways/api_spec.rb +1 -1
  88. data/spec/lib/flapjack/gateways/email_spec.rb +4 -4
  89. data/spec/lib/flapjack/gateways/jabber_spec.rb +77 -77
  90. data/spec/lib/flapjack/gateways/jsonapi/contact_methods_spec.rb +830 -0
  91. data/spec/lib/flapjack/gateways/jsonapi/entity_check_presenter_spec.rb +211 -0
  92. data/spec/lib/flapjack/gateways/jsonapi/entity_methods_spec.rb +863 -0
  93. data/spec/lib/flapjack/gateways/jsonapi/entity_presenter_spec.rb +108 -0
  94. data/spec/lib/flapjack/gateways/jsonapi_spec.rb +8 -0
  95. data/spec/lib/flapjack/gateways/oobetet_spec.rb +35 -35
  96. data/spec/lib/flapjack/gateways/pagerduty_spec.rb +40 -40
  97. data/spec/lib/flapjack/gateways/sms_messagenet_spec.rb +3 -3
  98. data/spec/lib/flapjack/gateways/web/views/check.html.erb_spec.rb +1 -1
  99. data/spec/lib/flapjack/gateways/web/views/contact.html.erb_spec.rb +5 -5
  100. data/spec/lib/flapjack/gateways/web/views/index.html.erb_spec.rb +1 -1
  101. data/spec/lib/flapjack/gateways/web_spec.rb +73 -74
  102. data/spec/lib/flapjack/logger_spec.rb +13 -13
  103. data/spec/lib/flapjack/pikelet_spec.rb +33 -33
  104. data/spec/lib/flapjack/processor_spec.rb +22 -22
  105. data/spec/lib/flapjack/redis_pool_spec.rb +1 -1
  106. data/spec/lib/flapjack/utility_spec.rb +12 -12
  107. data/spec/spec_helper.rb +9 -9
  108. data/spec/support/erb_view_helper.rb +4 -0
  109. metadata +107 -96
  110. data/lib/flapjack/gateways/web/public/css/flapjack.css +0 -49
  111. data/lib/flapjack/gateways/web/views/_css.html.erb +0 -42
  112. data/lib/flapjack/gateways/web/views/_foot.html.erb +0 -3
  113. data/lib/flapjack/gateways/web/views/_head.html.erb +0 -5
  114. data/lib/flapjack/gateways/web/views/_nav.html.erb +0 -10
@@ -17,16 +17,16 @@ describe 'Flapjack::Gateways::API::EntityPresenter' do
17
17
  let(:end_time) { time - (2 * 60 * 60) }
18
18
 
19
19
  def expect_check_presenters
20
- entity.should_receive(:name).exactly(4).times.and_return('foo')
21
- entity.should_receive(:check_list).and_return(['ping', 'ssh'])
22
- Flapjack::Data::EntityCheck.should_receive(:for_entity).
20
+ expect(entity).to receive(:name).exactly(4).times.and_return('foo')
21
+ expect(entity).to receive(:check_list).and_return(['ping', 'ssh'])
22
+ expect(Flapjack::Data::EntityCheck).to receive(:for_entity).
23
23
  with(entity, 'ssh', anything).and_return(check_a)
24
- Flapjack::Data::EntityCheck.should_receive(:for_entity).
24
+ expect(Flapjack::Data::EntityCheck).to receive(:for_entity).
25
25
  with(entity, 'ping', anything).and_return(check_b)
26
26
 
27
- Flapjack::Gateways::API::EntityCheckPresenter.should_receive(:new).
27
+ expect(Flapjack::Gateways::API::EntityCheckPresenter).to receive(:new).
28
28
  with(check_a).and_return(checkpres_a)
29
- Flapjack::Gateways::API::EntityCheckPresenter.should_receive(:new).
29
+ expect(Flapjack::Gateways::API::EntityCheckPresenter).to receive(:new).
30
30
  with(check_b).and_return(checkpres_b)
31
31
  end
32
32
 
@@ -35,13 +35,13 @@ describe 'Flapjack::Gateways::API::EntityPresenter' do
35
35
 
36
36
  status_a = double('status_a')
37
37
  status_b = double('status_b')
38
- checkpres_a.should_receive(:status).and_return(status_a)
39
- checkpres_b.should_receive(:status).and_return(status_b)
38
+ expect(checkpres_a).to receive(:status).and_return(status_a)
39
+ expect(checkpres_b).to receive(:status).and_return(status_b)
40
40
 
41
41
  ep = Flapjack::Gateways::API::EntityPresenter.new(entity)
42
42
  status = ep.status
43
- status.should == [{:entity => entity.name, :check => 'ping', :status => status_b},
44
- {:entity => entity.name, :check => 'ssh', :status => status_a}]
43
+ expect(status).to eq([{:entity => entity.name, :check => 'ping', :status => status_b},
44
+ {:entity => entity.name, :check => 'ssh', :status => status_a}])
45
45
 
46
46
  end
47
47
 
@@ -49,60 +49,60 @@ describe 'Flapjack::Gateways::API::EntityPresenter' do
49
49
  expect_check_presenters
50
50
  outages_a = double('outages_a')
51
51
  outages_b = double('outages_b')
52
- checkpres_a.should_receive(:outages).with(start_time, end_time).
52
+ expect(checkpres_a).to receive(:outages).with(start_time, end_time).
53
53
  and_return(outages_a)
54
- checkpres_b.should_receive(:outages).with(start_time, end_time).
54
+ expect(checkpres_b).to receive(:outages).with(start_time, end_time).
55
55
  and_return(outages_b)
56
56
 
57
57
  ep = Flapjack::Gateways::API::EntityPresenter.new(entity)
58
58
  outages = ep.outages(start_time, end_time)
59
- outages.should == [{:entity => entity.name, :check => 'ping', :outages => outages_b},
60
- {:entity => entity.name, :check => 'ssh', :outages => outages_a}]
59
+ expect(outages).to eq([{:entity => entity.name, :check => 'ping', :outages => outages_b},
60
+ {:entity => entity.name, :check => 'ssh', :outages => outages_a}])
61
61
  end
62
62
 
63
63
  it "returns a list of unscheduled maintenance periods for each check on an entity" do
64
64
  expect_check_presenters
65
65
  unsched_maint_a = double('unsched_maint_a')
66
66
  unsched_maint_b = double('unsched_maint_b')
67
- checkpres_a.should_receive(:unscheduled_maintenances).with(start_time, end_time).
67
+ expect(checkpres_a).to receive(:unscheduled_maintenances).with(start_time, end_time).
68
68
  and_return(unsched_maint_a)
69
- checkpres_b.should_receive(:unscheduled_maintenances).with(start_time, end_time).
69
+ expect(checkpres_b).to receive(:unscheduled_maintenances).with(start_time, end_time).
70
70
  and_return(unsched_maint_b)
71
71
 
72
72
  ep = Flapjack::Gateways::API::EntityPresenter.new(entity)
73
73
  unsched_maint = ep.unscheduled_maintenances(start_time, end_time)
74
- unsched_maint.should == [{:entity => entity.name, :check => 'ping', :unscheduled_maintenances => unsched_maint_b},
75
- {:entity => entity.name, :check => 'ssh', :unscheduled_maintenances => unsched_maint_a}]
74
+ expect(unsched_maint).to eq([{:entity => entity.name, :check => 'ping', :unscheduled_maintenances => unsched_maint_b},
75
+ {:entity => entity.name, :check => 'ssh', :unscheduled_maintenances => unsched_maint_a}])
76
76
  end
77
77
 
78
78
  it "returns a list of scheduled maintenance periods for each check on an entity" do
79
79
  expect_check_presenters
80
80
  sched_maint_a = double('sched_maint_a')
81
81
  sched_maint_b = double('sched_maint_b')
82
- checkpres_a.should_receive(:scheduled_maintenances).with(start_time, end_time).
82
+ expect(checkpres_a).to receive(:scheduled_maintenances).with(start_time, end_time).
83
83
  and_return(sched_maint_a)
84
- checkpres_b.should_receive(:scheduled_maintenances).with(start_time, end_time).
84
+ expect(checkpres_b).to receive(:scheduled_maintenances).with(start_time, end_time).
85
85
  and_return(sched_maint_b)
86
86
 
87
87
  ep = Flapjack::Gateways::API::EntityPresenter.new(entity)
88
88
  sched_maint = ep.scheduled_maintenances(start_time, end_time)
89
- sched_maint.should == [{:entity => entity.name, :check => 'ping', :scheduled_maintenances => sched_maint_b},
90
- {:entity => entity.name, :check => 'ssh', :scheduled_maintenances => sched_maint_a}]
89
+ expect(sched_maint).to eq([{:entity => entity.name, :check => 'ping', :scheduled_maintenances => sched_maint_b},
90
+ {:entity => entity.name, :check => 'ssh', :scheduled_maintenances => sched_maint_a}])
91
91
  end
92
92
 
93
93
  it "returns a list of downtime for each check on an entity" do
94
94
  expect_check_presenters
95
95
  downtime_a = double('downtime_a')
96
96
  downtime_b = double('downtime_b')
97
- checkpres_a.should_receive(:downtime).with(start_time, end_time).
97
+ expect(checkpres_a).to receive(:downtime).with(start_time, end_time).
98
98
  and_return(downtime_a)
99
- checkpres_b.should_receive(:downtime).with(start_time, end_time).
99
+ expect(checkpres_b).to receive(:downtime).with(start_time, end_time).
100
100
  and_return(downtime_b)
101
101
 
102
102
  ep = Flapjack::Gateways::API::EntityPresenter.new(entity)
103
103
  downtime = ep.downtime(start_time, end_time)
104
- downtime.should == [{:entity => entity.name, :check => 'ping', :downtime => downtime_b},
105
- {:entity => entity.name, :check => 'ssh', :downtime => downtime_a}]
104
+ expect(downtime).to eq([{:entity => entity.name, :check => 'ping', :downtime => downtime_b},
105
+ {:entity => entity.name, :check => 'ssh', :downtime => downtime_a}])
106
106
  end
107
107
 
108
108
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'flapjack/gateways/api'
3
3
 
4
- describe 'Flapjack::Gateways::API', :sinatra => true, :logger => true, :json => true do
4
+ describe 'Flapjack::Gateways::API', :sinatra => true, :logger => true do
5
5
 
6
6
  it "handles a route matching failure"
7
7
 
@@ -10,15 +10,15 @@ describe Flapjack::Gateways::Email, :logger => true do
10
10
  redis = double('redis')
11
11
 
12
12
  # TODO better checking of what gets passed here
13
- EM::P::SmtpClient.should_receive(:send).with(
13
+ expect(EM::P::SmtpClient).to receive(:send).with(
14
14
  hash_including(:host => 'localhost',
15
15
  :port => 25)).and_return(email)
16
16
 
17
17
  response = double(response)
18
- response.should_receive(:"respond_to?").with(:code).and_return(true)
19
- response.should_receive(:code).and_return(250)
18
+ expect(response).to receive(:"respond_to?").with(:code).and_return(true)
19
+ expect(response).to receive(:code).and_return(250)
20
20
 
21
- EM::Synchrony.should_receive(:sync).with(email).and_return(response)
21
+ expect(EM::Synchrony).to receive(:sync).with(email).and_return(response)
22
22
 
23
23
  notification = {'notification_type' => 'recovery',
24
24
  'contact_first_name' => 'John',
@@ -16,178 +16,178 @@ describe Flapjack::Gateways::Jabber, :logger => true do
16
16
  let(:stanza) { double('stanza') }
17
17
 
18
18
  it "hooks up event handlers to the appropriate methods" do
19
- Socket.should_receive(:gethostname).and_return('thismachine')
19
+ expect(Socket).to receive(:gethostname).and_return('thismachine')
20
20
 
21
- Flapjack::RedisPool.should_receive(:new)
21
+ expect(Flapjack::RedisPool).to receive(:new)
22
22
  fj = Flapjack::Gateways::Jabber.new(:config => config, :logger => @logger)
23
23
 
24
- EventMachine::Synchrony.should_receive(:next_tick).exactly(4).times.and_yield
24
+ expect(EventMachine::Synchrony).to receive(:next_tick).exactly(4).times.and_yield
25
25
 
26
- fj.should_receive(:register_handler).with(:ready).and_yield(stanza)
27
- fj.should_receive(:on_ready).with(stanza)
26
+ expect(fj).to receive(:register_handler).with(:ready).and_yield(stanza)
27
+ expect(fj).to receive(:on_ready).with(stanza)
28
28
 
29
- fj.should_receive(:register_handler).with(:message, :groupchat?, :body => /^flapjack:\s+/).and_yield(stanza)
30
- fj.should_receive(:on_groupchat).with(stanza)
29
+ expect(fj).to receive(:register_handler).with(:message, :groupchat?, :body => /^flapjack:\s+/).and_yield(stanza)
30
+ expect(fj).to receive(:on_groupchat).with(stanza)
31
31
 
32
- fj.should_receive(:register_handler).with(:message, :chat?).and_yield(stanza)
33
- fj.should_receive(:on_chat).with(stanza)
32
+ expect(fj).to receive(:register_handler).with(:message, :chat?).and_yield(stanza)
33
+ expect(fj).to receive(:on_chat).with(stanza)
34
34
 
35
- fj.should_receive(:register_handler).with(:disconnected).and_yield(stanza)
36
- fj.should_receive(:on_disconnect).with(stanza).and_return(true)
35
+ expect(fj).to receive(:register_handler).with(:disconnected).and_yield(stanza)
36
+ expect(fj).to receive(:on_disconnect).with(stanza).and_return(true)
37
37
 
38
38
  fj.setup
39
39
  end
40
40
 
41
41
  it "joins a chat room after connecting" do
42
- Flapjack::RedisPool.should_receive(:new)
42
+ expect(Flapjack::RedisPool).to receive(:new)
43
43
 
44
44
  fj = Flapjack::Gateways::Jabber.new(:config => config, :logger => @logger)
45
- fj.should_receive(:connected?).and_return(true)
45
+ expect(fj).to receive(:connected?).and_return(true)
46
46
 
47
- EventMachine::Synchrony.should_receive(:next_tick).and_yield
48
- fj.should_receive(:write).with(an_instance_of(Blather::Stanza::Presence))
49
- fj.should_receive(:write).with(an_instance_of(Blather::Stanza::Message))
47
+ expect(EventMachine::Synchrony).to receive(:next_tick).and_yield
48
+ expect(fj).to receive(:write).with(an_instance_of(Blather::Stanza::Presence))
49
+ expect(fj).to receive(:write).with(an_instance_of(Blather::Stanza::Message))
50
50
 
51
51
  fj.on_ready(stanza)
52
52
  end
53
53
 
54
54
  it "receives an acknowledgement message" do
55
- stanza.should_receive(:body).and_return('flapjack: ACKID 876 fixing now duration: 90m')
55
+ expect(stanza).to receive(:body).and_return('flapjack: ACKID 876 fixing now duration: 90m')
56
56
  from = double('from')
57
- from.should_receive(:stripped).and_return('sender')
58
- stanza.should_receive(:from).and_return(from)
57
+ expect(from).to receive(:stripped).and_return('sender')
58
+ expect(stanza).to receive(:from).and_return(from)
59
59
 
60
60
  redis = double('redis')
61
- redis.should_receive(:hget).with('unacknowledged_failures', '876').
61
+ expect(redis).to receive(:hget).with('unacknowledged_failures', '876').
62
62
  and_return('main-example.com:ping')
63
63
 
64
64
  entity_check = double(Flapjack::Data::EntityCheck)
65
- entity_check.should_receive(:in_unscheduled_maintenance?)
65
+ expect(entity_check).to receive(:in_unscheduled_maintenance?)
66
66
 
67
- Flapjack::Data::Event.should_receive(:create_acknowledgement).
67
+ expect(Flapjack::Data::Event).to receive(:create_acknowledgement).
68
68
  with('main-example.com', 'ping', :summary => 'fixing now',
69
69
  :acknowledgement_id => '876',
70
70
  :duration => (90 * 60), :redis => redis)
71
71
 
72
- Flapjack::Data::EntityCheck.should_receive(:for_event_id).
72
+ expect(Flapjack::Data::EntityCheck).to receive(:for_event_id).
73
73
  with('main-example.com:ping', :redis => redis).
74
74
  and_return(entity_check)
75
75
 
76
- Flapjack::RedisPool.should_receive(:new).and_return(redis)
76
+ expect(Flapjack::RedisPool).to receive(:new).and_return(redis)
77
77
  fj = Flapjack::Gateways::Jabber.new(:config => config, :logger => @logger)
78
78
 
79
- EventMachine::Synchrony.should_receive(:next_tick).and_yield
80
- fj.should_receive(:connected?).and_return(true)
81
- fj.should_receive(:write).with(an_instance_of(Blather::Stanza::Message))
79
+ expect(EventMachine::Synchrony).to receive(:next_tick).and_yield
80
+ expect(fj).to receive(:connected?).and_return(true)
81
+ expect(fj).to receive(:write).with(an_instance_of(Blather::Stanza::Message))
82
82
 
83
83
  fj.on_groupchat(stanza)
84
84
  end
85
85
 
86
86
  it "strips XML tags from the received message" do
87
- stanza.should_receive(:body).
87
+ expect(stanza).to receive(:body).
88
88
  and_return('flapjack: tell me about <span style="text-decoration: underline;">' +
89
89
  '<a href="http://example.org/">example.org</a></span>')
90
90
 
91
91
  from = double('from')
92
- from.should_receive(:stripped).and_return('sender')
93
- stanza.should_receive(:from).and_return(from)
92
+ expect(from).to receive(:stripped).and_return('sender')
93
+ expect(stanza).to receive(:from).and_return(from)
94
94
 
95
95
  redis = double('redis')
96
96
  entity = double(Flapjack::Data::Entity)
97
- entity.should_receive(:check_list).and_return(['ping'])
97
+ expect(entity).to receive(:check_list).and_return(['ping'])
98
98
 
99
- Flapjack::Data::Entity.should_receive(:find_by_name).with('example.org',
99
+ expect(Flapjack::Data::Entity).to receive(:find_by_name).with('example.org',
100
100
  :redis => redis).and_return(entity)
101
101
 
102
102
  entity_check = double(Flapjack::Data::EntityCheck)
103
- entity_check.should_receive(:current_maintenance).with(:scheduled => true).and_return(nil)
104
- entity_check.should_receive(:current_maintenance).with(:unscheduled => true).and_return(nil)
103
+ expect(entity_check).to receive(:current_maintenance).with(:scheduled => true).and_return(nil)
104
+ expect(entity_check).to receive(:current_maintenance).with(:unscheduled => true).and_return(nil)
105
105
 
106
- Flapjack::Data::EntityCheck.should_receive(:for_entity).with(entity, 'ping',
106
+ expect(Flapjack::Data::EntityCheck).to receive(:for_entity).with(entity, 'ping',
107
107
  :redis => redis).and_return(entity_check)
108
108
 
109
- Flapjack::RedisPool.should_receive(:new).and_return(redis)
109
+ expect(Flapjack::RedisPool).to receive(:new).and_return(redis)
110
110
  fj = Flapjack::Gateways::Jabber.new(:config => config, :logger => @logger)
111
111
 
112
- EventMachine::Synchrony.should_receive(:next_tick).and_yield
113
- fj.should_receive(:connected?).and_return(true)
114
- fj.should_receive(:write).with(an_instance_of(Blather::Stanza::Message))
112
+ expect(EventMachine::Synchrony).to receive(:next_tick).and_yield
113
+ expect(fj).to receive(:connected?).and_return(true)
114
+ expect(fj).to receive(:write).with(an_instance_of(Blather::Stanza::Message))
115
115
 
116
116
  fj.on_groupchat(stanza)
117
117
  end
118
118
 
119
119
  it "handles a message with a newline in it" do
120
- stanza.should_receive(:body).
120
+ expect(stanza).to receive(:body).
121
121
  and_return("flapjack: tell me about \nexample.com")
122
122
 
123
123
  from = double('from')
124
- from.should_receive(:stripped).and_return('sender')
125
- stanza.should_receive(:from).and_return(from)
124
+ expect(from).to receive(:stripped).and_return('sender')
125
+ expect(stanza).to receive(:from).and_return(from)
126
126
 
127
127
  redis = double('redis')
128
128
  entity = double(Flapjack::Data::Entity)
129
- entity.should_receive(:check_list).and_return(['ping'])
129
+ expect(entity).to receive(:check_list).and_return(['ping'])
130
130
 
131
- Flapjack::Data::Entity.should_receive(:find_by_name).with('example.com',
131
+ expect(Flapjack::Data::Entity).to receive(:find_by_name).with('example.com',
132
132
  :redis => redis).and_return(entity)
133
133
 
134
134
  entity_check = double(Flapjack::Data::EntityCheck)
135
- entity_check.should_receive(:current_maintenance).with(:scheduled => true).and_return(nil)
136
- entity_check.should_receive(:current_maintenance).with(:unscheduled => true).and_return(nil)
135
+ expect(entity_check).to receive(:current_maintenance).with(:scheduled => true).and_return(nil)
136
+ expect(entity_check).to receive(:current_maintenance).with(:unscheduled => true).and_return(nil)
137
137
 
138
- Flapjack::Data::EntityCheck.should_receive(:for_entity).with(entity, 'ping',
138
+ expect(Flapjack::Data::EntityCheck).to receive(:for_entity).with(entity, 'ping',
139
139
  :redis => redis).and_return(entity_check)
140
140
 
141
- Flapjack::RedisPool.should_receive(:new).and_return(redis)
141
+ expect(Flapjack::RedisPool).to receive(:new).and_return(redis)
142
142
  fj = Flapjack::Gateways::Jabber.new(:config => config, :logger => @logger)
143
143
 
144
- EventMachine::Synchrony.should_receive(:next_tick).and_yield
145
- fj.should_receive(:connected?).and_return(true)
146
- fj.should_receive(:write).with(an_instance_of(Blather::Stanza::Message))
144
+ expect(EventMachine::Synchrony).to receive(:next_tick).and_yield
145
+ expect(fj).to receive(:connected?).and_return(true)
146
+ expect(fj).to receive(:write).with(an_instance_of(Blather::Stanza::Message))
147
147
 
148
148
  fj.on_groupchat(stanza)
149
149
  end
150
150
 
151
151
  it "receives a message it doesn't understand" do
152
- stanza.should_receive(:body).once.and_return('flapjack: hello!')
152
+ expect(stanza).to receive(:body).once.and_return('flapjack: hello!')
153
153
  from = double('from')
154
- from.should_receive(:stripped).and_return('sender')
155
- stanza.should_receive(:from).and_return(from)
154
+ expect(from).to receive(:stripped).and_return('sender')
155
+ expect(stanza).to receive(:from).and_return(from)
156
156
 
157
- Flapjack::RedisPool.should_receive(:new)
157
+ expect(Flapjack::RedisPool).to receive(:new)
158
158
  fj = Flapjack::Gateways::Jabber.new(:config => config, :logger => @logger)
159
159
 
160
- EventMachine::Synchrony.should_receive(:next_tick).and_yield
161
- fj.should_receive(:connected?).and_return(true)
162
- fj.should_receive(:write).with(an_instance_of(Blather::Stanza::Message))
160
+ expect(EventMachine::Synchrony).to receive(:next_tick).and_yield
161
+ expect(fj).to receive(:connected?).and_return(true)
162
+ expect(fj).to receive(:write).with(an_instance_of(Blather::Stanza::Message))
163
163
 
164
164
  fj.on_groupchat(stanza)
165
165
  end
166
166
 
167
167
  it "reconnects when disconnected (if not quitting)" do
168
- Flapjack::RedisPool.should_receive(:new)
168
+ expect(Flapjack::RedisPool).to receive(:new)
169
169
  fj = Flapjack::Gateways::Jabber.new(:config => config, :logger => @logger)
170
170
 
171
171
  attempts = 0
172
172
 
173
- EventMachine::Synchrony.should_receive(:sleep).with(5).exactly(1).times
174
- EventMachine::Synchrony.should_receive(:sleep).with(2).exactly(3).times
175
- fj.should_receive(:connect).exactly(4).times.and_return {
173
+ expect(EventMachine::Synchrony).to receive(:sleep).with(5).exactly(1).times
174
+ expect(EventMachine::Synchrony).to receive(:sleep).with(2).exactly(3).times
175
+ expect(fj).to receive(:connect).exactly(4).times.and_return {
176
176
  attempts +=1
177
177
  raise StandardError.new unless attempts > 3
178
178
  }
179
179
 
180
180
  ret = fj.on_disconnect(stanza)
181
- ret.should be_true
181
+ expect(ret).to be true
182
182
  end
183
183
 
184
184
  it "prompts the blocking redis connection to quit" do
185
185
  shutdown_redis = double('shutdown_redis')
186
- shutdown_redis.should_receive(:rpush).with('jabber_notifications', %q{{"notification_type":"shutdown"}})
187
- EM::Hiredis.should_receive(:connect).and_return(shutdown_redis)
186
+ expect(shutdown_redis).to receive(:rpush).with('jabber_notifications', %q{{"notification_type":"shutdown"}})
187
+ expect(EM::Hiredis).to receive(:connect).and_return(shutdown_redis)
188
188
 
189
189
  redis = double('redis')
190
- Flapjack::RedisPool.should_receive(:new).and_return(redis)
190
+ expect(Flapjack::RedisPool).to receive(:new).and_return(redis)
191
191
  fj = Flapjack::Gateways::Jabber.new(:config => config, :logger => @logger)
192
192
 
193
193
  fj.stop
@@ -195,23 +195,23 @@ describe Flapjack::Gateways::Jabber, :logger => true do
195
195
 
196
196
  it "runs a blocking loop listening for notifications" do
197
197
  timer = double('timer')
198
- timer.should_receive(:cancel)
199
- EM::Synchrony.should_receive(:add_periodic_timer).with(1).and_return(timer)
198
+ expect(timer).to receive(:cancel)
199
+ expect(EM::Synchrony).to receive(:add_periodic_timer).with(1).and_return(timer)
200
200
 
201
201
  redis = double('redis')
202
202
 
203
- Flapjack::RedisPool.should_receive(:new).and_return(redis)
203
+ expect(Flapjack::RedisPool).to receive(:new).and_return(redis)
204
204
  fj = Flapjack::Gateways::Jabber.new(:config => config, :logger => @logger)
205
- fj.should_receive(:register_handler).exactly(4).times
205
+ expect(fj).to receive(:register_handler).exactly(4).times
206
206
 
207
- fj.should_receive(:connect)
208
- fj.should_receive(:connected?).exactly(3).times.and_return(true)
207
+ expect(fj).to receive(:connect)
208
+ expect(fj).to receive(:connected?).exactly(3).times.and_return(true)
209
209
 
210
210
  blpop_count = 0
211
211
 
212
212
  event_json = '{"notification_type":"problem","event_id":"main-example.com:ping",' +
213
213
  '"state":"critical","summary":"!!!","duration":43,"state_duration":76}'
214
- redis.should_receive(:blpop).twice {
214
+ expect(redis).to receive(:blpop).twice {
215
215
  blpop_count += 1
216
216
  if blpop_count == 1
217
217
  ["jabber_notifications", event_json]
@@ -221,13 +221,13 @@ describe Flapjack::Gateways::Jabber, :logger => true do
221
221
  end
222
222
  }
223
223
 
224
- EventMachine::Synchrony.should_receive(:next_tick).twice.and_yield
225
- fj.should_receive(:write).with(an_instance_of(Blather::Stanza::Message))
226
- fj.should_receive(:close)
224
+ expect(EventMachine::Synchrony).to receive(:next_tick).twice.and_yield
225
+ expect(fj).to receive(:write).with(an_instance_of(Blather::Stanza::Message))
226
+ expect(fj).to receive(:close)
227
227
 
228
228
  fj.start
229
229
 
230
- @logger.errors.should be_empty
230
+ expect(@logger.errors).to be_empty
231
231
  end
232
232
 
233
233
  end
@@ -0,0 +1,830 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/gateways/jsonapi'
3
+
4
+ describe 'Flapjack::Gateways::JSONAPI::ContactMethods', :sinatra => true, :logger => true do
5
+
6
+ def app
7
+ Flapjack::Gateways::JSONAPI
8
+ end
9
+
10
+ JSON_REQUEST_MIME = 'application/vnd.api+json'
11
+
12
+ let(:contact) { double(Flapjack::Data::Contact, :id => '21') }
13
+ let(:contact_core) {
14
+ {'id' => contact.id,
15
+ 'first_name' => "Ada",
16
+ 'last_name' => "Lovelace",
17
+ 'email' => "ada@example.com",
18
+ 'tags' => ["legend", "first computer programmer"]
19
+ }
20
+ }
21
+
22
+ let(:media) {
23
+ {'email' => 'ada@example.com',
24
+ 'sms' => '04123456789'
25
+ }
26
+ }
27
+
28
+ let(:media_intervals) {
29
+ {'email' => 500,
30
+ 'sms' => 300
31
+ }
32
+ }
33
+
34
+ let(:media_rollup_thresholds) {
35
+ {'email' => 5}
36
+ }
37
+
38
+ let(:redis) { double(::Redis) }
39
+
40
+ let(:notification_rule) {
41
+ double(Flapjack::Data::NotificationRule, :id => '1', :contact_id => '21')
42
+ }
43
+
44
+ let(:notification_rule_data) {
45
+ {"contact_id" => "21",
46
+ "tags" => ["database","physical"],
47
+ "entities" => ["foo-app-01.example.com"],
48
+ "time_restrictions" => nil,
49
+ "unknown_media" => ["jabber"],
50
+ "warning_media" => ["email"],
51
+ "critical_media" => ["sms", "email"],
52
+ "unknown_blackhole" => false,
53
+ "warning_blackhole" => false,
54
+ "critical_blackhole" => false
55
+ }
56
+ }
57
+
58
+ let(:semaphore) {
59
+ double(Flapjack::Data::Semaphore, :resource => 'folly',
60
+ :key => 'semaphores:folly', :expiry => 30, :token => 'spatulas-R-us')
61
+ }
62
+
63
+ before(:all) do
64
+ Flapjack::Gateways::JSONAPI.class_eval {
65
+ set :raise_errors, true
66
+ }
67
+ end
68
+
69
+ before(:each) do
70
+ expect(Flapjack::RedisPool).to receive(:new).and_return(redis)
71
+ Flapjack::Gateways::JSONAPI.instance_variable_set('@config', {})
72
+ Flapjack::Gateways::JSONAPI.instance_variable_set('@logger', @logger)
73
+ Flapjack::Gateways::JSONAPI.start
74
+ end
75
+
76
+ it "returns all the contacts" do
77
+ expect(Flapjack::Data::Contact).to receive(:entities_jsonapi).
78
+ with([contact.id], :redis => redis).and_return([[], {}])
79
+ expect(contact).to receive(:linked_entity_ids=).with(nil)
80
+ expect(contact).to receive(:to_json).and_return(contact_core.to_json)
81
+ expect(Flapjack::Data::Contact).to receive(:all).with(:redis => redis).
82
+ and_return([contact])
83
+
84
+ aget '/contacts'
85
+ expect(last_response).to be_ok
86
+ expect(last_response.body).to eq({:contacts => [contact_core]}.to_json)
87
+ end
88
+
89
+ it "returns the core information of a specified contact" do
90
+ expect(contact).to receive(:entities).and_return([])
91
+ expect(contact).to receive(:to_json).and_return(contact_core.to_json)
92
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
93
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
94
+
95
+ aget "/contacts/#{contact.id}"
96
+ expect(last_response).to be_ok
97
+ expect(last_response.body).to eq({:contacts => [contact_core]}.to_json)
98
+ end
99
+
100
+ it "does not return information for a contact that does not exist" do
101
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
102
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(nil)
103
+
104
+ aget "/contacts/#{contact.id}"
105
+ expect(last_response.status).to eq(404)
106
+ end
107
+
108
+ it "creates a contact with supplied ID" do
109
+ contact_data = {
110
+ "id" => "0362",
111
+ "first_name" => "John",
112
+ "last_name" => "Smith",
113
+ "email" => "johns@example.dom",
114
+ "media" => {
115
+ "email" => "johns@example.dom",
116
+ "jabber" => "johns@conference.localhost"
117
+ }
118
+ }
119
+
120
+ expect(Flapjack::Data::Semaphore).to receive(:new).
121
+ with("contact_mass_update", {:redis => redis, :expiry => 30}).and_return(semaphore)
122
+ expect(Flapjack::Data::Contact).to receive(:exists_with_id?).
123
+ with("0362", {:redis => redis}).and_return(false)
124
+ expect(Flapjack::Data::Contact).to receive(:add).
125
+ with(contact_data, {:redis => redis}).and_return(contact)
126
+ expect(semaphore).to receive(:release).and_return(true)
127
+
128
+ apost "/contacts", { :contacts => [contact_data]}.to_json,
129
+ {'CONTENT_TYPE' => JSON_REQUEST_MIME}
130
+
131
+ expect(last_response.status).to eq(200)
132
+ expect(last_response.body).to eq(["0362"].to_json)
133
+ end
134
+
135
+ it "updates a contact" do
136
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
137
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
138
+ expect(contact).to receive(:update)
139
+ expect(contact).to receive(:to_json).and_return('{"sausage": "good"}')
140
+
141
+ aput "/contacts/21", {:contacts => [{'sausage' => 'good'}]}.to_json,
142
+ {'CONTENT_TYPE' => JSON_REQUEST_MIME}
143
+ expect(last_response.status).to eq(200)
144
+ end
145
+
146
+ it "deletes a contact" do
147
+ end
148
+
149
+ it "does not create a contact if the data is improperly formatted" do
150
+ expect(Flapjack::Data::Contact).not_to receive(:add)
151
+
152
+ apost "/contacts", {'sausage' => 'good'}.to_json,
153
+ {'CONTENT_TYPE' => JSON_REQUEST_MIME}
154
+ expect(last_response.status).to eq(422)
155
+ end
156
+
157
+ it "does not update a contact if id exists in sent entity" do
158
+ contact_data = {'id' => '21'}
159
+ expect(Flapjack::Data::Contact).not_to receive(:find_by_id)
160
+ expect(Flapjack::Data::Contact).not_to receive(:update)
161
+
162
+ aput "/contacts/21", contact_data.to_json,
163
+ {'CONTENT_TYPE' => JSON_REQUEST_MIME}
164
+ expect(last_response.status).to eq(422)
165
+ end
166
+
167
+ it "replaces contacts with a submitted list" do
168
+ contacts = {'contacts' =>
169
+ [{"id" => "0362",
170
+ "first_name" => "John",
171
+ "last_name" => "Smith",
172
+ "email" => "johns@example.dom",
173
+ "media" => {"email" => "johns@example.dom",
174
+ "jabber" => "johns@conference.localhost"}},
175
+ {"id" => "0363",
176
+ "first_name" => "Jane",
177
+ "last_name" => "Jones",
178
+ "email" => "jane@example.dom",
179
+ "media" => {"email" => "jane@example.dom"}}
180
+ ]
181
+ }
182
+
183
+ expect(Flapjack::Data::Semaphore).to receive(:new).
184
+ with("contact_mass_update", {:redis => redis, :expiry => 30}).and_return(semaphore)
185
+ expect(Flapjack::Data::Contact).to receive(:all).with(:redis => redis).and_return([])
186
+ expect(Flapjack::Data::Contact).to receive(:add).twice
187
+ expect(semaphore).to receive(:release).and_return(true)
188
+
189
+ apost "/contacts_atomic", contacts.to_json, {'CONTENT_TYPE' => JSON_REQUEST_MIME}
190
+ expect(last_response.status).to eq(204)
191
+ end
192
+
193
+ it "does not replace contacts if the data is improperly formatted" do
194
+ expect(Flapjack::Data::Contact).not_to receive(:add)
195
+
196
+ apost "/contacts_atomic", {'contacts' => ["Hello", "again"]}.to_json,
197
+ {'CONTENT_TYPE' => JSON_REQUEST_MIME}
198
+ expect(last_response.status).to eq(422)
199
+ end
200
+
201
+ it "does not replace contacts if they don't contain an id in the source" do
202
+ contacts = {'contacts' =>
203
+ [{"id" => "0362",
204
+ "first_name" => "John",
205
+ "last_name" => "Smith",
206
+ "email" => "johns@example.dom",
207
+ "media" => {"email" => "johns@example.dom",
208
+ "jabber" => "johns@conference.localhost"}},
209
+ {"first_name" => "Jane",
210
+ "last_name" => "Jones",
211
+ "email" => "jane@example.dom",
212
+ "media" => {"email" => "jane@example.dom"}}
213
+ ]
214
+ }
215
+
216
+ expect(Flapjack::Data::Semaphore).to receive(:new).
217
+ with("contact_mass_update", {:redis => redis, :expiry => 30}).and_return(semaphore)
218
+ expect(Flapjack::Data::Contact).to receive(:all).with(:redis => redis).and_return([])
219
+ expect(Flapjack::Data::Contact).to receive(:add)
220
+ expect(semaphore).to receive(:release).and_return(true)
221
+
222
+ apost "/contacts_atomic", contacts.to_json, {'CONTENT_TYPE' => JSON_REQUEST_MIME}
223
+ expect(last_response.status).to eq(204)
224
+ end
225
+
226
+ it "updates a contact in a bulk replacement list if it is already present" do
227
+ contacts = {'contacts' =>
228
+ [{"id" => "0362",
229
+ "first_name" => "John",
230
+ "last_name" => "Smith",
231
+ "email" => "johns@example.dom",
232
+ "media" => {"email" => "johns@example.dom",
233
+ "jabber" => "johns@conference.localhost"}},
234
+ {"id" => "0363",
235
+ "first_name" => "Jane",
236
+ "last_name" => "Jones",
237
+ "email" => "jane@example.dom",
238
+ "media" => {"email" => "jane@example.dom"}}
239
+ ]
240
+ }
241
+
242
+ expect(Flapjack::Data::Semaphore).to receive(:new).
243
+ with("contact_mass_update", {:redis => redis, :expiry => 30}).and_return(semaphore)
244
+ existing = double(Flapjack::Data::Contact)
245
+ expect(existing).to receive(:id).and_return("0363")
246
+ expect(existing).to receive(:update).with(contacts['contacts'][1])
247
+
248
+ expect(Flapjack::Data::Contact).to receive(:all).with(:redis => redis).and_return([existing])
249
+ expect(Flapjack::Data::Contact).to receive(:add).with(contacts['contacts'][0], :redis => redis)
250
+ expect(semaphore).to receive(:release).and_return(true)
251
+
252
+ apost "/contacts_atomic", contacts.to_json, {'CONTENT_TYPE' => JSON_REQUEST_MIME}
253
+ expect(last_response.status).to eq(204)
254
+ end
255
+
256
+ it "deletes a contact not found in a bulk update list" do
257
+ contacts = {'contacts' =>
258
+ [{"id" => "0363",
259
+ "first_name" => "Jane",
260
+ "last_name" => "Jones",
261
+ "email" => "jane@example.dom",
262
+ "media" => {"email" => "jane@example.dom"}}
263
+ ]
264
+ }
265
+
266
+ expect(Flapjack::Data::Semaphore).to receive(:new).
267
+ with("contact_mass_update", {:redis => redis, :expiry => 30}).and_return(semaphore)
268
+ existing = double(Flapjack::Data::Contact)
269
+ expect(existing).to receive(:id).twice.and_return("0362")
270
+ expect(existing).to receive(:delete!)
271
+
272
+ expect(Flapjack::Data::Contact).to receive(:all).with(:redis => redis).and_return([existing])
273
+ expect(Flapjack::Data::Contact).to receive(:add).with(contacts['contacts'][0], :redis => redis)
274
+ expect(semaphore).to receive(:release).and_return(true)
275
+
276
+ apost "/contacts_atomic", contacts.to_json, {'CONTENT_TYPE' => JSON_REQUEST_MIME}
277
+ expect(last_response.status).to eq(204)
278
+ end
279
+
280
+ it "lists a contact's notification rules" do
281
+ notification_rule_2 = double(Flapjack::Data::NotificationRule, :id => '2', :contact_id => '21')
282
+ expect(notification_rule).to receive(:to_json).and_return('"rule_1"')
283
+ expect(notification_rule_2).to receive(:to_json).and_return('"rule_2"')
284
+ notification_rules = [ notification_rule, notification_rule_2 ]
285
+
286
+ expect(contact).to receive(:notification_rules).and_return(notification_rules)
287
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
288
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
289
+
290
+ aget "/contacts/#{contact.id}/notification_rules"
291
+ expect(last_response).to be_ok
292
+ expect(last_response.body).to eq('["rule_1","rule_2"]')
293
+ end
294
+
295
+ it "does not list notification rules for a contact that does not exist" do
296
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
297
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(nil)
298
+
299
+ aget "/contacts/#{contact.id}/notification_rules"
300
+ expect(last_response.status).to eq(404)
301
+ end
302
+
303
+ it "returns a specified notification rule" do
304
+ expect(notification_rule).to receive(:to_json).and_return('"rule_1"')
305
+ expect(Flapjack::Data::NotificationRule).to receive(:find_by_id).
306
+ with(notification_rule.id, {:redis => redis, :logger => @logger}).and_return(notification_rule)
307
+
308
+ aget "/notification_rules/#{notification_rule.id}"
309
+ expect(last_response).to be_ok
310
+ expect(last_response.body).to eq('{"notification_rules":["rule_1"]}')
311
+ end
312
+
313
+ it "does not return a notification rule that does not exist" do
314
+ expect(Flapjack::Data::NotificationRule).to receive(:find_by_id).
315
+ with(notification_rule.id, {:redis => redis, :logger => @logger}).and_return(nil)
316
+
317
+ aget "/notification_rules/#{notification_rule.id}"
318
+ expect(last_response.status).to eq(404)
319
+ end
320
+
321
+ # POST /notification_rules
322
+ it "creates a new notification rule" do
323
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
324
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
325
+ expect(notification_rule).to receive(:respond_to?).with(:critical_media).and_return(true)
326
+ expect(notification_rule).to receive(:to_json).and_return('"rule_1"')
327
+
328
+ # symbolize the keys
329
+ notification_rule_data_sym = notification_rule_data.inject({}){|memo,(k,v)|
330
+ memo[k.to_sym] = v; memo
331
+ }
332
+ notification_rule_data_sym.delete(:contact_id)
333
+
334
+ expect(contact).to receive(:add_notification_rule).
335
+ with(notification_rule_data_sym, :logger => @logger).and_return(notification_rule)
336
+
337
+ apost "/notification_rules", {"notification_rules" => [notification_rule_data]}.to_json,
338
+ {'CONTENT_TYPE' => JSON_REQUEST_MIME}
339
+ expect(last_response.status).to eq(201)
340
+ expect(last_response.body).to eq('{"notification_rules":["rule_1"]}')
341
+ end
342
+
343
+ it "does not create a notification_rule for a contact that's not present" do
344
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
345
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(nil)
346
+
347
+ apost "/notification_rules", {"notification_rules" => [notification_rule_data]}.to_json,
348
+ {'CONTENT_TYPE' => JSON_REQUEST_MIME}
349
+ expect(last_response.status).to eq(404)
350
+ end
351
+
352
+ it "does not create a notification_rule if a rule id is provided" do
353
+ expect(contact).not_to receive(:add_notification_rule)
354
+
355
+ apost "/notification_rules", {"notification_rules" => [notification_rule_data.merge(:id => 1)]}.to_json,
356
+ {'CONTENT_TYPE' => JSON_REQUEST_MIME}
357
+ expect(last_response.status).to eq(422)
358
+ end
359
+
360
+ # PUT /notification_rules/RULE_ID
361
+ it "updates a notification rule" do
362
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
363
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
364
+ expect(notification_rule).to receive(:to_json).and_return('"rule_1"')
365
+ expect(Flapjack::Data::NotificationRule).to receive(:find_by_id).
366
+ with(notification_rule.id, {:redis => redis, :logger => @logger}).and_return(notification_rule)
367
+
368
+ # symbolize the keys
369
+ notification_rule_data_sym = notification_rule_data.inject({}){|memo,(k,v)|
370
+ memo[k.to_sym] = v; memo
371
+ }
372
+ notification_rule_data_sym.delete(:contact_id)
373
+
374
+ expect(notification_rule).to receive(:update).with(notification_rule_data_sym, :logger => @logger).and_return(nil)
375
+
376
+ aput "/notification_rules/#{notification_rule.id}", {"notification_rules" => [notification_rule_data]}.to_json,
377
+ {'CONTENT_TYPE' => JSON_REQUEST_MIME}
378
+ expect(last_response).to be_ok
379
+ expect(last_response.body).to eq('{"notification_rules":["rule_1"]}')
380
+ end
381
+
382
+ it "does not update a notification rule that's not present" do
383
+ expect(Flapjack::Data::NotificationRule).to receive(:find_by_id).
384
+ with(notification_rule.id, {:redis => redis, :logger => @logger}).and_return(nil)
385
+
386
+ aput "/notification_rules/#{notification_rule.id}", {"notification_rules" => [notification_rule_data]}.to_json,
387
+ {'CONTENT_TYPE' => JSON_REQUEST_MIME}
388
+ expect(last_response.status).to eq(404)
389
+ end
390
+
391
+ it "does not update a notification_rule for a contact that's not present" do
392
+ expect(Flapjack::Data::NotificationRule).to receive(:find_by_id).
393
+ with(notification_rule.id, {:redis => redis, :logger => @logger}).and_return(notification_rule)
394
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
395
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(nil)
396
+
397
+ aput "/notification_rules/#{notification_rule.id}", {"notification_rules" => [notification_rule_data]}.to_json,
398
+ {'CONTENT_TYPE' => JSON_REQUEST_MIME}
399
+ expect(last_response.status).to eq(404)
400
+ end
401
+
402
+ # DELETE /notification_rules/RULE_ID
403
+ it "deletes a notification rule" do
404
+ expect(notification_rule).to receive(:contact_id).and_return(contact.id)
405
+ expect(Flapjack::Data::NotificationRule).to receive(:find_by_id).
406
+ with(notification_rule.id, {:redis => redis, :logger => @logger}).and_return(notification_rule)
407
+ expect(contact).to receive(:delete_notification_rule).with(notification_rule)
408
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
409
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
410
+
411
+ adelete "/notification_rules/#{notification_rule.id}"
412
+ expect(last_response.status).to eq(204)
413
+ end
414
+
415
+ it "does not delete a notification rule that's not present" do
416
+ expect(Flapjack::Data::NotificationRule).to receive(:find_by_id).
417
+ with(notification_rule.id, {:redis => redis, :logger => @logger}).and_return(nil)
418
+
419
+ adelete "/notification_rules/#{notification_rule.id}"
420
+ expect(last_response.status).to eq(404)
421
+ end
422
+
423
+ it "does not delete a notification rule if the contact is not present" do
424
+ expect(notification_rule).to receive(:contact_id).and_return(contact.id)
425
+ expect(Flapjack::Data::NotificationRule).to receive(:find_by_id).
426
+ with(notification_rule.id, {:redis => redis, :logger => @logger}).and_return(notification_rule)
427
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
428
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(nil)
429
+
430
+ adelete "/notification_rules/#{notification_rule.id}"
431
+ expect(last_response.status).to eq(404)
432
+ end
433
+
434
+ # GET /contacts/CONTACT_ID/media
435
+ it "returns the media of a contact" do
436
+ expect(contact).to receive(:media).and_return(media)
437
+ expect(contact).to receive(:media_intervals).and_return(media_intervals)
438
+ expect(contact).to receive(:media_rollup_thresholds).and_return(media_rollup_thresholds)
439
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
440
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
441
+ result = Hash[ *(media.keys.collect {|m|
442
+ [m, {'address' => media[m],
443
+ 'interval' => media_intervals[m],
444
+ 'rollup_threshold' => media_rollup_thresholds[m] }]
445
+ }).flatten(1)].to_json
446
+
447
+ aget "/contacts/#{contact.id}/media"
448
+ expect(last_response).to be_ok
449
+ expect(last_response.body).to eq(result)
450
+ end
451
+
452
+ it "does not return the media of a contact if the contact is not present" do
453
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
454
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(nil)
455
+
456
+ aget "/contacts/#{contact.id}/media"
457
+ expect(last_response.status).to eq(404)
458
+ end
459
+
460
+ # GET /contacts/CONTACT_ID/media/MEDIA
461
+ it "returns the specified media of a contact" do
462
+ expect(contact).to receive(:media).and_return(media)
463
+ expect(contact).to receive(:media_intervals).and_return(media_intervals)
464
+ expect(contact).to receive(:media_rollup_thresholds).and_return(media_rollup_thresholds)
465
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
466
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
467
+
468
+ result = {
469
+ 'address' => media['sms'],
470
+ 'interval' => media_intervals['sms'],
471
+ 'rollup_threshold' => media_rollup_thresholds['sms'],
472
+ }
473
+
474
+ aget "/contacts/#{contact.id}/media/sms"
475
+ expect(last_response).to be_ok
476
+ expect(last_response.body).to eq(result.to_json)
477
+ end
478
+
479
+ it "does not return the media of a contact if the contact is not present" do
480
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
481
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(nil)
482
+
483
+ aget "/contacts/#{contact.id}/media/sms"
484
+ expect(last_response.status).to eq(404)
485
+ end
486
+
487
+ it "does not return the media of a contact if the media is not present" do
488
+ expect(contact).to receive(:media).and_return(media)
489
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
490
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
491
+
492
+ aget "/contacts/#{contact.id}/media/telepathy"
493
+ expect(last_response.status).to eq(404)
494
+ end
495
+
496
+ # PUT, DELETE /contacts/CONTACT_ID/media/MEDIA
497
+ it "creates/updates a media of a contact" do
498
+ # as far as API is concerned these are the same -- contact.rb spec test
499
+ # may distinguish between them
500
+ alt_media = media.merge('sms' => '04987654321')
501
+ alt_media_intervals = media_intervals.merge('sms' => '200')
502
+ alt_media_rollup_thresholds = media_rollup_thresholds.merge('sms' => '5')
503
+
504
+ expect(contact).to receive(:set_address_for_media).with('sms', '04987654321')
505
+ expect(contact).to receive(:set_interval_for_media).with('sms', '200')
506
+ expect(contact).to receive(:set_rollup_threshold_for_media).with('sms', '5')
507
+ expect(contact).to receive(:media).and_return(alt_media)
508
+ expect(contact).to receive(:media_intervals).and_return(alt_media_intervals)
509
+ expect(contact).to receive(:media_rollup_thresholds).and_return(alt_media_rollup_thresholds)
510
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
511
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
512
+
513
+ result = {'address' => alt_media['sms'],
514
+ 'interval' => alt_media_intervals['sms'],
515
+ 'rollup_threshold' => alt_media_rollup_thresholds['sms']}
516
+
517
+ aput "/contacts/#{contact.id}/media/sms", :address => '04987654321',
518
+ :interval => '200', :rollup_threshold => '5'
519
+ expect(last_response).to be_ok
520
+ expect(last_response.body).to eq(result.to_json)
521
+ end
522
+
523
+ it "updates a contact's pagerduty media credentials" do
524
+ result = {'service_key' => "flapjacktest@conference.jabber.sausage.net",
525
+ 'subdomain' => "sausage.pagerduty.com",
526
+ 'username' => "sausage@example.com",
527
+ 'password' => "sausage"}
528
+
529
+ expect(contact).to receive(:set_pagerduty_credentials).with(result)
530
+ expect(contact).to receive(:pagerduty_credentials).and_return(result)
531
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
532
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
533
+
534
+ aput "/contacts/#{contact.id}/media/pagerduty", :service_key => result['service_key'],
535
+ :subdomain => result['subdomain'], :username => result['username'],
536
+ :password => result['password']
537
+
538
+ expect(last_response).to be_ok
539
+ expect(last_response.body).to eq(result.to_json)
540
+ end
541
+
542
+ it "does not create a media of a contact that's not present" do
543
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
544
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(nil)
545
+
546
+ aput "/contacts/#{contact.id}/media/sms", :address => '04987654321', :interval => '200'
547
+ expect(last_response.status).to eq(404)
548
+ end
549
+
550
+ it "does not create a media of a contact if no address is provided" do
551
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
552
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
553
+
554
+ aput "/contacts/#{contact.id}/media/sms", :interval => '200'
555
+ expect(last_response.status).to eq(422)
556
+ end
557
+
558
+ it "creates a media of a contact even if no interval is provided" do
559
+ alt_media = media.merge('sms' => '04987654321')
560
+ alt_media_intervals = media_intervals.merge('sms' => nil)
561
+ alt_media_rollup_thresholds = media_rollup_thresholds.merge('sms' => nil)
562
+
563
+ expect(contact).to receive(:set_address_for_media).with('sms', '04987654321')
564
+ expect(contact).to receive(:set_interval_for_media).with('sms', nil)
565
+ expect(contact).to receive(:set_rollup_threshold_for_media).with("sms", nil)
566
+ expect(contact).to receive(:media).and_return(alt_media)
567
+ expect(contact).to receive(:media_intervals).and_return(alt_media_intervals)
568
+ expect(contact).to receive(:media_rollup_thresholds).and_return(alt_media_rollup_thresholds)
569
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
570
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
571
+
572
+ aput "/contacts/#{contact.id}/media/sms", :address => '04987654321'
573
+ expect(last_response).to be_ok
574
+ end
575
+
576
+ it "deletes a media of a contact" do
577
+ expect(contact).to receive(:remove_media).with('sms')
578
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
579
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
580
+
581
+ adelete "/contacts/#{contact.id}/media/sms"
582
+ expect(last_response.status).to eq(204)
583
+ end
584
+
585
+ it "does not delete a media of a contact that's not present" do
586
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
587
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(nil)
588
+
589
+ adelete "/contacts/#{contact.id}/media/sms"
590
+ expect(last_response.status).to eq(404)
591
+ end
592
+
593
+ # GET /contacts/CONTACT_ID/timezone
594
+ it "returns the timezone of a contact" do
595
+ expect(contact).to receive(:timezone).and_return(::ActiveSupport::TimeZone.new('Australia/Sydney'))
596
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
597
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
598
+
599
+ aget "/contacts/#{contact.id}/timezone"
600
+ expect(last_response).to be_ok
601
+ expect(last_response.body).to eq('"Australia/Sydney"')
602
+ end
603
+
604
+ it "doesn't get the timezone of a contact that doesn't exist" do
605
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
606
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(nil)
607
+
608
+ aget "/contacts/#{contact.id}/timezone"
609
+ expect(last_response.status).to eq(404)
610
+ end
611
+
612
+ # PUT /contacts/CONTACT_ID/timezone
613
+ it "sets the timezone of a contact" do
614
+ expect(contact).to receive(:timezone=).with('Australia/Perth')
615
+ expect(contact).to receive(:timezone).and_return(ActiveSupport::TimeZone.new('Australia/Perth'))
616
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
617
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
618
+
619
+ aput "/contacts/#{contact.id}/timezone", {:timezone => 'Australia/Perth'}
620
+ expect(last_response).to be_ok
621
+ end
622
+
623
+ it "doesn't set the timezone of a contact who can't be found" do
624
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
625
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(nil)
626
+
627
+ aput "/contacts/#{contact.id}/timezone", {:timezone => 'Australia/Perth'}
628
+ expect(last_response.status).to eq(404)
629
+ end
630
+
631
+ # DELETE /contacts/CONTACT_ID/timezone
632
+ it "deletes the timezone of a contact" do
633
+ expect(contact).to receive(:timezone=).with(nil)
634
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
635
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
636
+
637
+ adelete "/contacts/#{contact.id}/timezone"
638
+ expect(last_response.status).to eq(204)
639
+ end
640
+
641
+ it "does not delete the timezone of a contact that's not present" do
642
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
643
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(nil)
644
+
645
+ adelete "/contacts/#{contact.id}/timezone"
646
+ expect(last_response.status).to eq(404)
647
+ end
648
+
649
+ it "sets a single tag on a contact and returns current tags" do
650
+ expect(contact).to receive(:add_tags).with('web')
651
+ expect(contact).to receive(:tags).and_return(['web'])
652
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
653
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
654
+
655
+ apost "contacts/#{contact.id}/tags", {:tags => ['web']}.to_json, {'CONTENT_TYPE' => JSON_REQUEST_MIME}
656
+ expect(last_response).to be_ok
657
+ expect(last_response.body).to eq({:tags => ['web']}.to_json)
658
+ end
659
+
660
+ it "does not set a single tag on a contact that's not found" do
661
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
662
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(nil)
663
+
664
+ apost "contacts/#{contact.id}/tags", {:tags => ['web']}.to_json, {'CONTENT_TYPE' => JSON_REQUEST_MIME}
665
+ expect(last_response.status).to eq(404)
666
+ end
667
+
668
+ it "sets multiple tags on a contact and returns current tags" do
669
+ expect(contact).to receive(:add_tags).with('web', 'app')
670
+ expect(contact).to receive(:tags).and_return(['web', 'app'])
671
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
672
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
673
+
674
+ apost "contacts/#{contact.id}/tags", {:tags => ['web', 'app']}.to_json, {'CONTENT_TYPE' => JSON_REQUEST_MIME}
675
+ expect(last_response).to be_ok
676
+ expect(last_response.body).to eq({:tags => ['web', 'app']}.to_json)
677
+ end
678
+
679
+ it "does not set multiple tags on a contact that's not found" do
680
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
681
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(nil)
682
+
683
+ apost "contacts/#{contact.id}/tags", {:tags => ['web', 'app']}.to_json, {'CONTENT_TYPE' => JSON_REQUEST_MIME}
684
+ expect(last_response.status).to eq(404)
685
+ end
686
+
687
+ it "removes a single tag from a contact" do
688
+ expect(contact).to receive(:delete_tags).with('web')
689
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
690
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
691
+
692
+ adelete "contacts/#{contact.id}/tags", {:tags => ['web']}.to_json, {'CONTENT_TYPE' => JSON_REQUEST_MIME}
693
+ expect(last_response.status).to eq(204)
694
+ end
695
+
696
+ it "does not remove a single tag from a contact that's not found" do
697
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
698
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(nil)
699
+
700
+ adelete "contacts/#{contact.id}/tags", {:tags => ['web']}.to_json, {'CONTENT_TYPE' => JSON_REQUEST_MIME}
701
+ expect(last_response.status).to eq(404)
702
+ end
703
+
704
+ it "removes multiple tags from a contact" do
705
+ expect(contact).to receive(:delete_tags).with('web', 'app')
706
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
707
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
708
+
709
+ adelete "contacts/#{contact.id}/tags", {:tags => ['web', 'app']}.to_json, {'CONTENT_TYPE' => JSON_REQUEST_MIME}
710
+ expect(last_response.status).to eq(204)
711
+ end
712
+
713
+ it "does not remove multiple tags from a contact that's not found" do
714
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
715
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(nil)
716
+
717
+ adelete "contacts/#{contact.id}/tags", {:tags => ['web', 'app']}.to_json, {'CONTENT_TYPE' => JSON_REQUEST_MIME}
718
+ expect(last_response.status).to eq(404)
719
+ end
720
+
721
+ it "gets all tags on a contact" do
722
+ expect(contact).to receive(:tags).and_return(['web', 'app'])
723
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
724
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
725
+
726
+ aget "contacts/#{contact.id}/tags"
727
+ expect(last_response).to be_ok
728
+ expect(last_response.body).to eq({"tags"=>['web', 'app']}.to_json)
729
+ end
730
+
731
+ it "does not get all tags on a contact that's not found" do
732
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
733
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(nil)
734
+
735
+ aget "contacts/#{contact.id}/tags"
736
+ expect(last_response.status).to eq(404)
737
+ end
738
+
739
+ it "gets all entity tags for a contact" do
740
+ entity_1 = double(Flapjack::Data::Entity)
741
+ expect(entity_1).to receive(:name).and_return('entity_1')
742
+ entity_2 = double(Flapjack::Data::Entity)
743
+ expect(entity_2).to receive(:name).and_return('entity_2')
744
+ tag_data = [{:entity => entity_1, :tags => ['web']},
745
+ {:entity => entity_2, :tags => ['app']}]
746
+ expect(contact).to receive(:entities).with(:tags => true).
747
+ and_return(tag_data)
748
+
749
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
750
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
751
+
752
+ aget "contacts/#{contact.id}/entity_tags"
753
+ expect(last_response).to be_ok
754
+ tag_response = {'entity_1' => ['web'],
755
+ 'entity_2' => ['app']}
756
+ expect(last_response.body).to eq(tag_response.to_json)
757
+ end
758
+
759
+ it "does not get all entity tags for a contact that's not found" do
760
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
761
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(nil)
762
+
763
+ aget "contacts/#{contact.id}/entity_tags"
764
+ expect(last_response.status).to eq(404)
765
+ end
766
+
767
+ it "adds tags to multiple entities for a contact" do
768
+ entity_1 = double(Flapjack::Data::Entity)
769
+ expect(entity_1).to receive(:name).twice.and_return('entity_1')
770
+ expect(entity_1).to receive(:add_tags).with('web')
771
+ entity_2 = double(Flapjack::Data::Entity)
772
+ expect(entity_2).to receive(:name).twice.and_return('entity_2')
773
+ expect(entity_2).to receive(:add_tags).with('app')
774
+
775
+ entities = [{:entity => entity_1}, {:entity => entity_2}]
776
+ expect(contact).to receive(:entities).and_return(entities)
777
+ tag_data = [{:entity => entity_1, :tags => ['web']},
778
+ {:entity => entity_2, :tags => ['app']}]
779
+ expect(contact).to receive(:entities).with(:tags => true).and_return(tag_data)
780
+
781
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
782
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
783
+
784
+ apost "contacts/#{contact.id}/entity_tags",
785
+ :entity => {'entity_1' => ['web'], 'entity_2' => ['app']}
786
+ expect(last_response).to be_ok
787
+ tag_response = {'entity_1' => ['web'],
788
+ 'entity_2' => ['app']}
789
+ expect(last_response.body).to eq(tag_response.to_json)
790
+ end
791
+
792
+ it "does not add tags to multiple entities for a contact that's not found" do
793
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
794
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(nil)
795
+
796
+ apost "contacts/#{contact.id}/entity_tags",
797
+ :entity => {'entity_1' => ['web'], 'entity_2' => ['app']}
798
+ expect(last_response.status).to eq(404)
799
+ end
800
+
801
+ it "deletes tags from multiple entities for a contact" do
802
+ entity_1 = double(Flapjack::Data::Entity)
803
+ expect(entity_1).to receive(:name).and_return('entity_1')
804
+ expect(entity_1).to receive(:delete_tags).with('web')
805
+ entity_2 = double(Flapjack::Data::Entity)
806
+ expect(entity_2).to receive(:name).and_return('entity_2')
807
+ expect(entity_2).to receive(:delete_tags).with('app')
808
+
809
+ entities = [{:entity => entity_1}, {:entity => entity_2}]
810
+ expect(contact).to receive(:entities).and_return(entities)
811
+
812
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
813
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(contact)
814
+
815
+ adelete "contacts/#{contact.id}/entity_tags",
816
+ :entity => {'entity_1' => ['web'], 'entity_2' => ['app']}
817
+ expect(last_response.status).to eq(204)
818
+ end
819
+
820
+ it "does not delete tags from multiple entities for a contact that's not found" do
821
+ expect(Flapjack::Data::Contact).to receive(:find_by_id).
822
+ with(contact.id, {:redis => redis, :logger => @logger}).and_return(nil)
823
+
824
+ adelete "contacts/#{contact.id}/entity_tags",
825
+ :entity => {'entity_1' => ['web'], 'entity_2' => ['app']}
826
+ expect(last_response.status).to eq(404)
827
+ end
828
+
829
+
830
+ end