newman 0.1.1 → 0.2.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.
- data/CHANGELOG.md +23 -0
- data/Gemfile +3 -0
- data/README.md +126 -7
- data/examples/config/dreamhost.rb.example +5 -1
- data/examples/config/gmail.rb.example +4 -0
- data/examples/live_test.rb +4 -7
- data/examples/simple_mailing_list.rb +2 -2
- data/lib/newman.rb +97 -1
- data/lib/newman/application.rb +238 -1
- data/lib/newman/controller.rb +93 -8
- data/lib/newman/email_logger.rb +54 -0
- data/lib/newman/filters.rb +123 -0
- data/lib/newman/mailer.rb +98 -32
- data/lib/newman/mailing_list.rb +83 -0
- data/lib/newman/recorder.rb +132 -0
- data/lib/newman/request_logger.rb +41 -0
- data/lib/newman/response_logger.rb +41 -0
- data/lib/newman/server.rb +197 -23
- data/lib/newman/settings.rb +72 -4
- data/lib/newman/store.rb +68 -4
- data/lib/newman/test_mailer.rb +79 -6
- data/lib/newman/version.rb +5 -2
- data/test/helper.rb +18 -0
- data/{examples → test/integration}/acid_tests.rb +30 -20
- data/test/integration/skip_response_test.rb +22 -0
- data/test/integration/subject_filter_test.rb +25 -0
- data/test/settings.rb +4 -0
- data/test/suite.rb +6 -0
- metadata +74 -9
- data/lib/newman/commands.rb +0 -72
- data/lib/newman/store/recorder.rb +0 -63
data/lib/newman/mailing_list.rb
CHANGED
@@ -1,29 +1,112 @@
|
|
1
|
+
# `Newman::MailingList` implements a simple mechanism for storing lists of email
|
2
|
+
# addresses keyed by a mailing list name.
|
3
|
+
#
|
4
|
+
# This object is meant to be used in conjunction with a
|
5
|
+
# `Newman::Store` object which is `PStore` backed, but would fairly easily map to
|
6
|
+
# arbitrary data stores via adapter objects.
|
7
|
+
#
|
8
|
+
# `Newman::MailingList` is part of Newman's **external interface**.
|
9
|
+
|
1
10
|
module Newman
|
2
11
|
class MailingList
|
12
|
+
|
13
|
+
# ---
|
14
|
+
|
15
|
+
# To initialize a `Newman::MailingList` object, a list name and a store object must
|
16
|
+
# be provided, i.e:
|
17
|
+
#
|
18
|
+
# store = Newman::Store.new('simple.store')
|
19
|
+
# mailing_list = Newman::MailingList.new("simple_list", store)
|
20
|
+
|
3
21
|
def initialize(name, store)
|
4
22
|
self.name = name
|
5
23
|
self.store = store
|
6
24
|
end
|
7
25
|
|
26
|
+
# ---
|
27
|
+
|
28
|
+
# `Newman::MailingList#subscribe` is used to add subscribers to
|
29
|
+
# the mailing list, i.e.
|
30
|
+
#
|
31
|
+
# mailing_list.subscribe('gregory.t.brown@gmail.com')
|
32
|
+
#
|
33
|
+
# If the provided email address is for a new subscriber, a new record gets
|
34
|
+
# created for that subscriber, adding them to the list. Otherwise, this
|
35
|
+
# method does not modify the mailing list.
|
36
|
+
#
|
37
|
+
# Returns true if list was modified, returns false otherwise.
|
38
|
+
|
8
39
|
def subscribe(email)
|
40
|
+
return false if subscriber?(email)
|
41
|
+
|
9
42
|
store[name].create(email)
|
43
|
+
|
44
|
+
true
|
10
45
|
end
|
11
46
|
|
47
|
+
# ---
|
48
|
+
|
49
|
+
# `Newman::MailingList#unsubscribe` is used to remove subscribers from
|
50
|
+
# the mailing list, i.e.
|
51
|
+
#
|
52
|
+
# mailing_list.unsubscribe('gregory.t.brown@gmail.com')
|
53
|
+
#
|
54
|
+
# If the provided email address is for an existing subscriber, the record
|
55
|
+
# for that subscriber is destroyed, removing them from the list.
|
56
|
+
# Otherwise, this method does not modify the mailing list.
|
57
|
+
#
|
58
|
+
# Returns true if list was modified, returns false otherwise.
|
59
|
+
|
12
60
|
def unsubscribe(email)
|
61
|
+
return false unless subscriber?(email)
|
62
|
+
|
13
63
|
record = store[name].find { |e| e.contents == email }
|
14
64
|
store[name].destroy(record.id)
|
65
|
+
|
66
|
+
true
|
15
67
|
end
|
16
68
|
|
69
|
+
|
70
|
+
# ---
|
71
|
+
|
72
|
+
# `Newman::MailingList#subscriber?` is used to check if a given email address
|
73
|
+
# is on the list, i.e.
|
74
|
+
#
|
75
|
+
# mailing_list.subscriber?('gregory.t.brown@gmail.com')
|
76
|
+
#
|
77
|
+
# Returns true if a record is found which matches the given email address,
|
78
|
+
# returns false otherwise.
|
79
|
+
|
17
80
|
def subscriber?(email)
|
18
81
|
store[name].any? { |r| r.contents == email }
|
19
82
|
end
|
20
83
|
|
84
|
+
# ---
|
85
|
+
|
86
|
+
# `Newman::MailingList#subscribers` is used to access all email addresses for
|
87
|
+
# the mailing list's subscribers, i.e:
|
88
|
+
#
|
89
|
+
# members = mailing_list.subscribers
|
90
|
+
#
|
91
|
+
# Returns an array of email addresses.
|
92
|
+
|
21
93
|
def subscribers
|
22
94
|
store[name].map { |r| r.contents }
|
23
95
|
end
|
24
96
|
|
97
|
+
# ---
|
98
|
+
|
99
|
+
# **NOTE: Methods below this point in the file are implementation
|
100
|
+
# details, and should not be depended upon.**
|
101
|
+
|
25
102
|
private
|
26
103
|
|
104
|
+
# ---
|
105
|
+
|
106
|
+
# These accessors have been made private to reflect the fact that
|
107
|
+
# `Newman::MailingList` objects are meant to point to a single
|
108
|
+
# named list within a single data store once they are created.
|
109
|
+
|
27
110
|
attr_accessor :name, :store
|
28
111
|
end
|
29
112
|
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# `Newman::Recorder` provides a simple mechanism for storing non-relational
|
2
|
+
# records within a `Newman::Store` with autoincrementing identifiers. It
|
3
|
+
# supports basic CRUD operations, and also acts as an `Enumerable` object.
|
4
|
+
#
|
5
|
+
# For an example of how to make use of `Newman::Recorder` to implement arbitrary
|
6
|
+
# persistent models, be sure to check out the implementation of the
|
7
|
+
# `Newman::MailingList` object.
|
8
|
+
#
|
9
|
+
# `Newman::Recorder` is part of Newman's **external interface**.
|
10
|
+
|
11
|
+
module Newman
|
12
|
+
Record = Struct.new(:column, :id, :contents)
|
13
|
+
|
14
|
+
class Recorder
|
15
|
+
include Enumerable
|
16
|
+
|
17
|
+
# ---
|
18
|
+
|
19
|
+
# To initialize a `Newman::Recorder` object, a `column` key
|
20
|
+
# and `store` object must be provided, i.e.
|
21
|
+
#
|
22
|
+
# store = Newman::Store.new("sample.store")
|
23
|
+
# recorder = Newman::Recorder.new(:subscribers, store)
|
24
|
+
#
|
25
|
+
# However, in most cases you should not instantiate a
|
26
|
+
# `Newman::Recorder` directly, and instead should make use of
|
27
|
+
# `Newman::Store#[]` which is syntactic sugar for the same operation.
|
28
|
+
#
|
29
|
+
# The first time a particular `column` key is referenced, two mapping
|
30
|
+
# is created for the column in the underlying data store: one which
|
31
|
+
# keeps track of the autoincrementing ids, and one that keeps track
|
32
|
+
# of the data stored within the column. It's fine to treat these
|
33
|
+
# mappings as implementation details, but we treat them as part of Newman's
|
34
|
+
# external interface because backwards-incompatible changes to them will
|
35
|
+
# result in possible data store corruption.
|
36
|
+
|
37
|
+
def initialize(column, store)
|
38
|
+
self.column = column
|
39
|
+
self.store = store
|
40
|
+
|
41
|
+
store.write do |data|
|
42
|
+
data[:identifiers][column] ||= 0
|
43
|
+
data[:columns][column] ||= {}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# ---
|
48
|
+
|
49
|
+
# `Newman::Recorder#each` iterates over all records stored in the column,
|
50
|
+
# yielding a `Newman::Record` object for each one. Because `Enumerable` is
|
51
|
+
# mixed into `Newman::Recorder`, all enumerable methods that get called on a
|
52
|
+
# recorder object end up making calls to this method.
|
53
|
+
def each
|
54
|
+
store.read do |data|
|
55
|
+
data[:columns][column].each do |id, contents|
|
56
|
+
yield(Record.new(column, id, contents))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# ---
|
62
|
+
|
63
|
+
# `Newman::Recorder#create` store an arbitrary Ruby object in the data
|
64
|
+
# store and returns a `Newman::Record` object which has fields for the
|
65
|
+
# `column` key, record `id`, and record `contents`. This method
|
66
|
+
# automatically generates new ids, starting with `id=1` for the
|
67
|
+
# first record and then incrementing sequentially.
|
68
|
+
|
69
|
+
def create(contents)
|
70
|
+
store.write do |data|
|
71
|
+
id = (data[:identifiers][column] += 1)
|
72
|
+
|
73
|
+
data[:columns][column][id] = contents
|
74
|
+
|
75
|
+
Record.new(column, id, contents)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# ---
|
80
|
+
|
81
|
+
# `Newman::Recorder#read` looks up a record by `id` and returns a
|
82
|
+
# `Newman::Record` object.
|
83
|
+
|
84
|
+
def read(id)
|
85
|
+
store.read do |data|
|
86
|
+
Record.new(column, id, data[:columns][column][id])
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# ---
|
91
|
+
|
92
|
+
# `Newman::Recorder#update` looks up a record by `id` and yields its
|
93
|
+
# contents. The record contents are then replaced with the
|
94
|
+
# return value of the provided block.
|
95
|
+
|
96
|
+
def update(id)
|
97
|
+
store.write do |data|
|
98
|
+
data[:columns][column][id] = yield(data[:columns][column][id])
|
99
|
+
|
100
|
+
Record.new(column, id, data[:columns][column][id])
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# ---
|
105
|
+
|
106
|
+
# `Newman::Recorder#destroy` looks up a record by `id` and then removes it
|
107
|
+
# from the data store. This method returns `true` whether or not a record
|
108
|
+
# was actually destroyed, which is a somewhat useless behavior and may
|
109
|
+
# need to be fixed in a future version of Newman. Patches welcome!
|
110
|
+
|
111
|
+
def destroy(id)
|
112
|
+
store.write do |data|
|
113
|
+
data[:columns][column].delete(id)
|
114
|
+
end
|
115
|
+
|
116
|
+
true
|
117
|
+
end
|
118
|
+
|
119
|
+
# ---
|
120
|
+
|
121
|
+
# **NOTE: Methods below this point in the file are implementation
|
122
|
+
# details, and should not be depended upon**
|
123
|
+
private
|
124
|
+
|
125
|
+
# ---
|
126
|
+
|
127
|
+
# These accessors have been made private to reflect the fac that
|
128
|
+
# `Newman::Recorder` objects are meant to point to a single column within a
|
129
|
+
# single data store once created.
|
130
|
+
attr_accessor :column, :store
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# `Newman::RequestLogger` implements rudimentary request logging functionality,
|
2
|
+
# which is enabled by default when `Newman::Server.simple` is used to execute
|
3
|
+
# your applications.
|
4
|
+
#
|
5
|
+
# If you are only interested in making use of this logging functionality and not
|
6
|
+
# extending it or changing it in some way, you do not need to be familiar with
|
7
|
+
# the code in this file. Just be sure to note that if you add
|
8
|
+
# `service.debug_mode = true` to your configuration file, or set the Ruby
|
9
|
+
# `$DEBUG` global variable, you will get much more verbose output from
|
10
|
+
# Newman's logging system.
|
11
|
+
#
|
12
|
+
# `Newman::RequestLogger` is part of Newman's **internal interface**.
|
13
|
+
|
14
|
+
module Newman
|
15
|
+
RequestLogger = Object.new
|
16
|
+
|
17
|
+
# ---
|
18
|
+
|
19
|
+
# `Newman::RequestLogger` is implemented as a singleton object and is
|
20
|
+
# completely stateless in nature. It can be added directly as an app to
|
21
|
+
# any `Newman::Server` instance. The `Newman::Server.simple` helper method
|
22
|
+
# automatically places a `Newman::RequestLogger` at the beginning of the call chain,
|
23
|
+
# but it can be inserted at any point and will output the request email
|
24
|
+
# object at that point in the call chain.
|
25
|
+
|
26
|
+
class << RequestLogger
|
27
|
+
include EmailLogger
|
28
|
+
|
29
|
+
# ---
|
30
|
+
|
31
|
+
# `Newman::RequestLogger#call` simply delegates to
|
32
|
+
# `Newman::EmailLogger#log_email`, passing it a logger instance, the
|
33
|
+
# `"REQUEST"` prefix for the log line, and an instance
|
34
|
+
# of an email object. See `Newman::Server.tick` and `Newman::EmailLogger#log_email`
|
35
|
+
# for details.
|
36
|
+
|
37
|
+
def call(params)
|
38
|
+
log_email(params[:logger], "REQUEST", params[:request])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# `Newman::ResponseLogger` supports rudimentary response logging functionality, which is
|
2
|
+
# enabled by default when `Newman::Server.simple` is used to execute your
|
3
|
+
# applications.
|
4
|
+
#
|
5
|
+
# If you are only interested in making use of this logging functionality and not
|
6
|
+
# extending it or changing it in some way, you do not need to be familiar with
|
7
|
+
# the code in this file. Just be sure to note that if you add
|
8
|
+
# `service.debug_mode = true` to your configuration file, or set the Ruby
|
9
|
+
# `$DEBUG` global variable, you will get much more verbose output from
|
10
|
+
# Newman's logging system.
|
11
|
+
#
|
12
|
+
# `Newman::ResponseLogger` is part of Newman's **internal interface**.
|
13
|
+
|
14
|
+
module Newman
|
15
|
+
ResponseLogger = Object.new
|
16
|
+
|
17
|
+
# ---
|
18
|
+
|
19
|
+
# `Newman::ResponseLogger` is implemented as a singleton object and is
|
20
|
+
# completely stateless in nature. It can be added directly as an app to
|
21
|
+
# any `Newman::Server` instance. The `Newman::Server.simple` helper method
|
22
|
+
# automatically places a `ResponseLogger` at the end of the call chain, but
|
23
|
+
# it can be inserted at any point and will output the response email object
|
24
|
+
# at that point in the call chain.
|
25
|
+
|
26
|
+
class << ResponseLogger
|
27
|
+
include EmailLogger
|
28
|
+
|
29
|
+
# ---
|
30
|
+
|
31
|
+
# `Newman::ResponseLogger#call` simply delegates to
|
32
|
+
# `EmailLogger#log_email`, passing it a logger instance, the
|
33
|
+
# `"RESPONSE"` prefix for the log line, and an instance of an email
|
34
|
+
# object. See `Newman::Server.tick` and `Newman::EmailLogger#log_email`
|
35
|
+
# for details.
|
36
|
+
|
37
|
+
def call(params)
|
38
|
+
log_email(params[:logger], "RESPONSE", params[:response])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/newman/server.rb
CHANGED
@@ -1,45 +1,219 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
# `Newman::Server` takes incoming mesages from a mailer object and passes them
|
2
|
+
# to applications as a request, and then delivers a response email after the
|
3
|
+
# applications have modified it.
|
4
|
+
#
|
5
|
+
# A `Newman::Server` object can be used in three distinct ways:
|
6
|
+
#
|
7
|
+
# 1) Instantiated via `Newman::Server.test_mode` and then run tick by tick
|
8
|
+
# in integration tests.
|
9
|
+
#
|
10
|
+
# 2) Instantiated via `Newman::Server.simple` which immediately executes
|
11
|
+
# an infinite polling loop.
|
12
|
+
#
|
13
|
+
# 3) Instantiated explicitly and manually configured, for maximum control.
|
14
|
+
#
|
15
|
+
# All of these different workflows are supported, but if you are simply looking
|
16
|
+
# to build applications with `Newman`, you are most likely going to end up using
|
17
|
+
# `Newman::Server.simple` because it takes care of most of the setup work for
|
18
|
+
# you and is the easiest way to run a single Newman application.
|
19
|
+
#
|
20
|
+
# `Newman::Server` is part of Newman's **external interface**.
|
6
21
|
|
7
|
-
|
8
|
-
|
9
|
-
|
22
|
+
module Newman
|
23
|
+
class Server
|
24
|
+
# ---
|
25
|
+
|
26
|
+
# `Newman::Server.simple` automatically generates a `Newman::Mailer` object
|
27
|
+
# and `Newman::Settings` object from the privded `settings_file`. These
|
28
|
+
# objects are then passed on to `Newman::Server.new` and a server instance
|
29
|
+
# is created. The server object is set up to run the specified `app`, with
|
30
|
+
# request and response logging support enabled. Calling this method puts
|
31
|
+
# the server in an infinite polling loop, because its final action is to
|
32
|
+
# call `Newman::Server.run`.
|
33
|
+
#
|
34
|
+
# The following example demonstrates how to use this method:
|
35
|
+
#
|
36
|
+
# ping_pong = Newman::Application.new do
|
37
|
+
# subject(:match, "ping") do
|
38
|
+
# respond(:subject => "pong")
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# default do
|
42
|
+
# respond(:subject => "You missed the ball!")
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# Newman::Server.simple(ping_pong, "config/environment.rb")
|
47
|
+
#
|
48
|
+
# Given a properly configured settings file, this code will launch a polling
|
49
|
+
# server and run the simple `ping_pong` application.
|
10
50
|
|
11
|
-
|
51
|
+
def self.simple(app, settings_file)
|
52
|
+
settings = Settings.from_file(settings_file)
|
53
|
+
mailer = Mailer.new(settings)
|
54
|
+
server = new(settings, mailer)
|
55
|
+
server.apps = [RequestLogger, app, ResponseLogger]
|
56
|
+
|
57
|
+
server.run
|
58
|
+
end
|
59
|
+
|
60
|
+
# ---
|
61
|
+
|
62
|
+
# `Newman::Server.test_mode` automatically generates a `Newman::TestMailer` object
|
63
|
+
# and `Newman::Settings` object from the provided `settings_file`. These
|
64
|
+
# objects are then passed on to `Newman::Server.new` and a server instance
|
65
|
+
# which is preconfigured for use in integration testing is returned.
|
66
|
+
#
|
67
|
+
# Using the application from the `Newman::Server.simple` documentation
|
68
|
+
# above, it'd be possible to write a simple integration test using this
|
69
|
+
# method in the following way:
|
70
|
+
#
|
71
|
+
# server = Newman::Server.test_mode("config/environment.rb")
|
72
|
+
# server.apps << ping_pong
|
73
|
+
#
|
74
|
+
# mailer = server.mailer
|
75
|
+
# mailer.deliver_message(:to => "test@test.com",
|
76
|
+
# :subject => "ping)
|
77
|
+
#
|
78
|
+
# server.tick
|
79
|
+
#
|
80
|
+
# mailer.messages.first.subject.must_equal("pong")
|
81
|
+
#
|
82
|
+
# It's worth mentioning that although `Newman::Server.test_mode` is part of
|
83
|
+
# Newman's external interface, the `Newman::TestMailer` object is considered part
|
84
|
+
# of its internals. This is due to some ugly issues with global state and
|
85
|
+
# the overall brittleness of the current implementation. Expect a bit of
|
86
|
+
# weirdness if you plan to use this feature, at least until we improve upon
|
87
|
+
# it.
|
88
|
+
|
89
|
+
def self.test_mode(settings_file)
|
90
|
+
settings = Settings.from_file(settings_file)
|
91
|
+
mailer = TestMailer.new(settings)
|
92
|
+
|
93
|
+
new(settings, mailer)
|
12
94
|
end
|
13
95
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
96
|
+
# ---
|
97
|
+
|
98
|
+
# To initialize a `Newman::Server` object, a settings object and mailer object must
|
99
|
+
# be provided, and a logger object may also be provided. If a logger object
|
100
|
+
# is not provided, `Newman::Server#default_logger` is called to create one.
|
101
|
+
#
|
102
|
+
# Instantiating a server object directly can be useful for building live
|
103
|
+
# integration tests, or for building cron jobs which process email
|
104
|
+
# periodically rather than in a busy-wait loop. See one of Newman's [live
|
105
|
+
# tests](https://github.com/mendicant-university/newman/blob/master/examples/live_test.rb)
|
106
|
+
# for an example of how this approach works.
|
19
107
|
|
20
|
-
|
108
|
+
def initialize(settings, mailer, logger=nil)
|
109
|
+
self.settings = settings
|
110
|
+
self.mailer = mailer
|
111
|
+
self.logger = logger || default_logger
|
112
|
+
self.apps = []
|
21
113
|
end
|
22
114
|
|
23
|
-
|
115
|
+
# ---
|
116
|
+
|
117
|
+
# These accessors are mostly meant for use with server objects under test
|
118
|
+
# mode, or server objects that have been explicitly instantiated. If you are
|
119
|
+
# using `Newman::Server.simple` to run your apps, it's safe to treat these
|
120
|
+
# as an implementation detail; all important data will get passed down
|
121
|
+
# into your apps on each `tick`.
|
122
|
+
|
123
|
+
attr_accessor :settings, :mailer, :apps, :logger
|
124
|
+
|
125
|
+
# ---
|
126
|
+
|
127
|
+
# `Newman::Server.run` kicks off a busy wait loop, alternating between
|
128
|
+
# calling `Newman::Server.tick` and sleeping for the amount of time
|
129
|
+
# specified by `settings.service.polling_interval`. We originally planned to
|
130
|
+
# use an EventMachine periodic timer here to potentially make running
|
131
|
+
# several servers within a single process easier, but had trouble coming up
|
132
|
+
# with a use case that made the extra dependency worth it.
|
133
|
+
|
134
|
+
def run
|
24
135
|
loop do
|
25
|
-
tick
|
136
|
+
tick
|
26
137
|
sleep settings.service.polling_interval
|
27
138
|
end
|
28
139
|
end
|
29
140
|
|
30
|
-
|
31
|
-
|
141
|
+
# ---
|
142
|
+
|
143
|
+
# `Newman::Server.tick` runs the following sequence for each incoming
|
144
|
+
# request.
|
145
|
+
#
|
146
|
+
# 1) A response is generated with the TO field set to the FROM field of the
|
147
|
+
# request, and the FROM field set to `settings.service.default_sender`.
|
148
|
+
# Applications can change these values later, but these are sensible
|
149
|
+
# defaults that work for most common needs.
|
150
|
+
#
|
151
|
+
# 2) The list of `apps` is iterated over sequentially, and each
|
152
|
+
# application's `call` method is invoked with a parameters hash which
|
153
|
+
# include the `request` email, the `response` email, the `settings` object
|
154
|
+
# being used by the server, and the `logger` object being used by the
|
155
|
+
# server.
|
156
|
+
#
|
157
|
+
# 2a) If any application raises an exception, that exception is caught and
|
158
|
+
# the processing of the current request is halted. Details about the failure
|
159
|
+
# are logged and if `settings.service.raise_exceptions` is enabled, the
|
160
|
+
# exception is re-raised, typically taking the server down with it. This
|
161
|
+
# setting is off by default.
|
162
|
+
#
|
163
|
+
# 3) Assuming an exception is not encountered, the response is delivered.
|
164
|
+
|
165
|
+
def tick
|
166
|
+
mailer.messages.each do |request|
|
32
167
|
response = mailer.new_message(:to => request.from,
|
33
168
|
:from => settings.service.default_sender)
|
169
|
+
|
170
|
+
begin
|
171
|
+
apps.each do |app|
|
172
|
+
app.call(:request => request,
|
173
|
+
:response => response,
|
174
|
+
:settings => settings,
|
175
|
+
:logger => logger)
|
176
|
+
end
|
177
|
+
rescue StandardError => e
|
178
|
+
logger.info("FAIL") { e.to_s }
|
179
|
+
logger.debug("FAIL") { "#{e.inspect}\n"+e.backtrace.join("\n ") }
|
34
180
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
181
|
+
if settings.service.raise_exceptions
|
182
|
+
raise
|
183
|
+
else
|
184
|
+
next
|
185
|
+
end
|
39
186
|
end
|
40
187
|
|
41
188
|
response.deliver
|
42
189
|
end
|
43
190
|
end
|
191
|
+
|
192
|
+
# ---
|
193
|
+
|
194
|
+
# **NOTE: Methods below this point in the file are implementation
|
195
|
+
# details, and should not be depended upon**
|
196
|
+
|
197
|
+
private
|
198
|
+
|
199
|
+
# ---
|
200
|
+
|
201
|
+
# `Newman::Server#default_logger` generates a logger object using
|
202
|
+
# Ruby's standard library. This object outputs to `STDERR`, and
|
203
|
+
# runs at info level by default, but will run at debug level if
|
204
|
+
# either `settings.service.debug_mode` or the Ruby `$DEBUG`
|
205
|
+
# variable is set.
|
206
|
+
|
207
|
+
def default_logger
|
208
|
+
self.logger = Logger.new(STDERR)
|
209
|
+
|
210
|
+
if settings.service.debug_mode || $DEBUG
|
211
|
+
logger.level = Logger::DEBUG
|
212
|
+
else
|
213
|
+
logger.level = Logger::INFO
|
214
|
+
end
|
215
|
+
|
216
|
+
logger
|
217
|
+
end
|
44
218
|
end
|
45
219
|
end
|