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