forked from ministryofjustice/peoplefinder
-
Notifications
You must be signed in to change notification settings - Fork 2
/
smoke_test
executable file
·197 lines (170 loc) · 5.11 KB
/
smoke_test
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#!/usr/bin/env ruby
# Peoplefinder smoke test
# =======================
#
# Set the following environment variables:
#
# * HOST - the root of the server to be tested, e.g. http://example.com/
# * EMAIL_ADDRESS - the email address to sign in with
# * EMAIL_PASSWORD - the IMAP password
#
# Google Apps IMAP is assumed, and the account must have IMAP access
# configured. For the password, generate an app-specific password (this is
# necessary if two-factor authentication is enabled).
#
# Run the test:
#
# $ bundle exec ./smoke_test
#
# Successful output will look like this:
#
# Request token ... OK
# Fetch token email ... wait 2s ... OK
# Sign in ... OK
# Edit profile ... OK
# Search for profile ... wait 2s ... OK
#
# On success, the return code is zero. Failure will result in a non-zero return
# code.
require 'bundler/setup'
require 'capybara'
require 'capybara/dsl'
require 'capybara/poltergeist'
require 'mail'
require 'net/imap'
require 'securerandom'
host = ENV.fetch('HOST')
email_address = ENV.fetch('EMAIL_ADDRESS')
email_password = ENV.fetch('EMAIL_PASSWORD')
search_name = ENV.fetch('SEARCH_NAME')
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, phantomjs_options: ['--ignore-ssl-errors=yes'])
end
Capybara.run_server = false
Capybara.current_driver = :poltergeist
Capybara.app_host = host
# rubocop:disable ClassLength
class SmokeTest
include Capybara::DSL
TIME_DRIFT_ALLOWANCE = 5
def initialize(email_address, imap, host, search_name)
@email_address = email_address
@imap = imap
@host = host
@search_name = search_name
@start_time = Time.now.utc
end
# rubocop:disable MethodLength
def run
step 'Request token' do
# 300 secs is the TTL for the DNS based maintenance page
with_retries(initial_delay: 15, max_delay: 60) { request_token }
# request_token
end
signin_path = nil
step 'Fetch token email' do
token_mail = with_retries(initial_delay: 5, max_delay: 120) { fetch_token_mail }
fail "couldn't find token email" unless token_mail
text_part = token_mail.text_part.decoded
signin_path = text_part[%r{/tokens/[0-9a-f-]+}]
fail "couldn't find sign-in token link" unless signin_path
end
my_name = nil
step 'Sign in' do
sign_in signin_path
my_name = find_own_name
end
unique_string = SecureRandom.uuid
step 'Edit profile' do
update_profile my_name, unique_string
end
step 'Search for own changed profile' do
found = with_retries { search_profile my_name, unique_string }
fail "couldn't find own profile via search" unless found
end
step "Search for profile: #{@search_name}" do
found = with_retries { search_profile @search_name, @search_name }
fail "couldn't find profile for #{@search_name} via search" unless found
end
rescue => e
puts page.text
raise e
end
private
attr_reader :imap, :email_address
def find_own_name
page.text[/Signed in as (.*?) Sign out/, 1].tap { |name|
fail "couldn't find own name" unless name
}
end
def search_profile(name, search_term)
visit '/'
fill_in 'Enter the name of a person or role', with: search_term
click_button 'Submit search'
result = nil
within '#search_results' do
result = page.has_text?(name)
end
result
end
def update_profile(name, uuid)
desc = "Smoke test started at #{@start_time.iso8601}\n\nUnique identifier: #{uuid}"
click_link name, match: :first
click_link 'Edit this profile'
fill_in 'Extra information', with: desc
click_button 'Save', match: :first
fail "couldn't update profile" unless page.has_text?('Updated your profile')
end
def request_token
visit '/'
page_loaded = page.has_text?('Request link to access People Finder')
if page_loaded
fill_in 'Email address', with: email_address
click_button 'Request link'
end
page_loaded
end
def fetch_token_mail
imap.examine 'INBOX'
candidate_ids = imap.search(['SINCE', @start_time.strftime('%-d-%b-%Y')])
mails = candidate_ids.map { |id|
msg = imap.fetch(id, 'RFC822')[0].attr['RFC822']
Mail.read_from_string(msg)
}
mails.reverse.find { |mail|
mail.subject =~ /access request/i &&
mail.date.to_time >= (@start_time - TIME_DRIFT_ALLOWANCE) &&
mail.text_part.decoded.include?(@host)
}
end
def sign_in(path)
visit path
fail "couldn't sign in via #{path}" unless page.body =~ /Signed in as/
end
def with_retries(tries: 5, initial_delay: 2, max_delay: 30)
delay = initial_delay
result = nil
tries.times do
result = yield
break if result
wait delay
delay = [max_delay, delay * 2].min
end
result
end
def wait(delay)
$stdout.print "wait #{delay} ... "
$stdout.flush
sleep delay
end
def step(s)
$stdout.print s, ' ... '
$stdout.flush
yield.tap { $stdout.puts 'OK' }
end
end
imap = Net::IMAP.new('imap.gmail.com', port: 993, ssl: true)
imap.login email_address, email_password
SmokeTest.new(email_address, imap, host, search_name).run
imap.logout
imap.disconnect