From eac3056c237d523f4786593922fe8f88eb65dff7 Mon Sep 17 00:00:00 2001 From: elijah Date: Tue, 29 Mar 2016 13:27:01 -0700 Subject: testing: adds mx delivery tests --- lib/leap_cli/macros/hosts.rb | 22 +++ provider_base/services/_api_tester.json | 13 ++ provider_base/services/monitor.rb | 3 + provider_base/services/mx.json | 2 +- provider_base/services/mx.rb | 1 + provider_base/services/soledad.rb | 22 ++- provider_base/services/webapp.json | 10 +- puppet/modules/site_config/templates/hosts | 3 +- .../site_postfix/manifests/mx/static_aliases.pp | 2 +- .../modules/site_webapp/templates/config.yml.erb | 3 +- tests/helpers/bonafide_helper.rb | 190 +++++++++++++++++---- tests/helpers/couchdb_helper.rb | 36 ++++ tests/helpers/http_helper.rb | 27 ++- tests/helpers/smtp_helper.rb | 45 +++++ tests/helpers/srp_helper.rb | 4 +- tests/order.rb | 7 +- tests/white-box/couchdb.rb | 27 +++ tests/white-box/mx.rb | 99 ++++++++++- tests/white-box/webapp.rb | 18 +- 19 files changed, 460 insertions(+), 74 deletions(-) create mode 100644 provider_base/services/_api_tester.json create mode 100644 provider_base/services/monitor.rb create mode 100644 provider_base/services/mx.rb create mode 100644 tests/helpers/smtp_helper.rb diff --git a/lib/leap_cli/macros/hosts.rb b/lib/leap_cli/macros/hosts.rb index 8281329f..541bbc13 100644 --- a/lib/leap_cli/macros/hosts.rb +++ b/lib/leap_cli/macros/hosts.rb @@ -3,6 +3,24 @@ module LeapCli module Macro + ## + ## IPs + ## + + # + # returns a simple array of all the IPs for the specified node list + # + def host_ips(node_list) + if self.vagrant? + node_list = node_list['environment' => 'local'] + else + node_list = node_list['environment' => '!local'] + end + node_list.map {|name, n| + [n.ip_address, (global.facts[name]||{})['ec2_public_ipv4']] + }.flatten.compact.uniq + end + ## ## HOSTS ## @@ -48,6 +66,10 @@ module LeapCli 'domain_full' => node.domain.full, 'port' => node.ssh.port } + if node.dns['aliases'] && node.dns['aliases'].any? + # include aliases, but without domain.full + hosts[node.name]['aliases'] = node.dns['aliases'] - [node.domain.full] + end node_location = node['location'] ? node['location']['name'] : nil if my_location == node_location if facts = @node.manager.facts[node.name] diff --git a/provider_base/services/_api_tester.json b/provider_base/services/_api_tester.json new file mode 100644 index 00000000..790aa7d8 --- /dev/null +++ b/provider_base/services/_api_tester.json @@ -0,0 +1,13 @@ +// +// This partial should be added to any service that runs tests that rely on +// accessing the bonafide webapp API. +// +{ + "testing": { + "monitor_auth_token": "= secret :api_monitor_auth_token", + "api_uri": "= global.services[:webapp].api.uri", + // api_hosts is not used directly, but calling hostnames() will ensure + // that the hostnames are added to /etc/hosts + "api_hosts": "= hostnames(nodes_like_me[:services => 'webapp'])" + } +} \ No newline at end of file diff --git a/provider_base/services/monitor.rb b/provider_base/services/monitor.rb new file mode 100644 index 00000000..01590d5c --- /dev/null +++ b/provider_base/services/monitor.rb @@ -0,0 +1,3 @@ +unless self.services.include? "webapp" + LeapCli.log :error, "service `monitor` requires service `webapp` on the same node (node #{self.name})." +end diff --git a/provider_base/services/mx.json b/provider_base/services/mx.json index 676e075b..c7e99d85 100644 --- a/provider_base/services/mx.json +++ b/provider_base/services/mx.json @@ -30,7 +30,7 @@ "password": "= secret :couch_leap_mx_password", "salt": "= hex_secret :couch_leap_mx_password_salt, 128" }, - "mynetworks": "= nodes['environment' => '!local'].map{|name, n| [n.ip_address, (global.facts[name]||{})['ec2_public_ipv4']]}.flatten.compact.uniq", + "mynetworks": "= host_ips(nodes)", "rbls": ["zen.spamhaus.org"], "clamav": { "whitelisted_addresses": [] diff --git a/provider_base/services/mx.rb b/provider_base/services/mx.rb new file mode 100644 index 00000000..741ff313 --- /dev/null +++ b/provider_base/services/mx.rb @@ -0,0 +1 @@ +apply_partial('services/_api_tester.json') diff --git a/provider_base/services/soledad.rb b/provider_base/services/soledad.rb index b55e90b6..4391dead 100644 --- a/provider_base/services/soledad.rb +++ b/provider_base/services/soledad.rb @@ -1,3 +1,23 @@ unless self.services.include? "couchdb" LeapCli.log :error, "service `soledad` requires service `couchdb` on the same node (node #{self.name})." -end \ No newline at end of file +end + +# +# currently, mx tests keep the same test user around, +# by rely on the soledad test to destroy the email +# test user's mail storage (so that it does not just +# keep accumulating test emails). +# +# We do it this way because: +# +# (1) couchdb bloats if you create and destroy test users, +# so we keep the test user around. +# +# (2) the mx test has access to the bonafide api, but the +# bonafide api (webapp) does not have access to destroy +# user storage dbs. +# +# If any of these conditions change, then this partial +# will no longer be required. +# +apply_partial('services/_api_tester.json') \ No newline at end of file diff --git a/provider_base/services/webapp.json b/provider_base/services/webapp.json index 9e3d751b..b1d2ca59 100644 --- a/provider_base/services/webapp.json +++ b/provider_base/services/webapp.json @@ -33,7 +33,11 @@ "support" ], "locales": "= provider.languages", - "default_locale": "= provider.default_language" + "default_locale": "= provider.default_language", + "api_tokens": { + "monitor": "= secret :api_monitor_auth_token", + "allowed_ips": "= host_ips(nodes_like_me)" + } }, "stunnel": { "clients": { @@ -55,8 +59,10 @@ "service_type": "public_service", "api": { "domain": "= 'api.' + webapp.domain", + "version": 1, "port": 4430, - "ca_cert_uri": "= 'https://' + webapp.domain + '/ca.crt'" + "ca_cert_uri": "= 'https://' + webapp.domain + '/ca.crt'", + "uri": "= %(https://#{api.domain}:#{api.port}/#{api.version})" }, "nickserver": { "domain": "= 'nicknym.' + domain.full_suffix", diff --git a/puppet/modules/site_config/templates/hosts b/puppet/modules/site_config/templates/hosts index d557f730..d62cbc3f 100644 --- a/puppet/modules/site_config/templates/hosts +++ b/puppet/modules/site_config/templates/hosts @@ -6,7 +6,8 @@ <%- if @hosts then -%> <% @hosts.keys.sort.each do |name| -%> <%- props = @hosts[name] -%> -<%= props["ip_address"] %> <%= props["domain_full"] %> <%= props["domain_internal"] %> <%= name %> +<%- aliases = props["aliases"] ? props["aliases"].join(' ') : nil -%> +<%= [props["ip_address"], props["domain_full"], props["domain_internal"], aliases, name].compact.uniq.join(' ') %> <% end -%> <% end -%> diff --git a/puppet/modules/site_postfix/manifests/mx/static_aliases.pp b/puppet/modules/site_postfix/manifests/mx/static_aliases.pp index 71c0555a..9cd7ca02 100644 --- a/puppet/modules/site_postfix/manifests/mx/static_aliases.pp +++ b/puppet/modules/site_postfix/manifests/mx/static_aliases.pp @@ -40,7 +40,7 @@ class site_postfix::mx::static_aliases { $local_aliases = [ 'admin', 'administrator', 'bin', 'cron', 'games', 'ftp', 'lp', 'maildrop', 'mysql', 'news', 'nobody', 'noc', 'postgresql', 'ssladmin', 'sys', - 'usenet', 'uucp', 'www', 'www-data' + 'usenet', 'uucp', 'www', 'www-data', 'leap-mx' ] postfix::mailalias { diff --git a/puppet/modules/site_webapp/templates/config.yml.erb b/puppet/modules/site_webapp/templates/config.yml.erb index c2e9f3df..dd55d3e9 100644 --- a/puppet/modules/site_webapp/templates/config.yml.erb +++ b/puppet/modules/site_webapp/templates/config.yml.erb @@ -22,7 +22,8 @@ production = { "service_levels" => @webapp['service_levels'], "allow_registration" => @webapp['allow_registration'], "handle_blacklist" => @webapp['forbidden_usernames'], - "invite_required" => @webapp['invite_required'] + "invite_required" => @webapp['invite_required'], + "api_tokens" => @webapp['api_tokens'] } if @webapp['engines'] && @webapp['engines'].any? diff --git a/tests/helpers/bonafide_helper.rb b/tests/helpers/bonafide_helper.rb index 20c3ca8d..95e3e3b7 100644 --- a/tests/helpers/bonafide_helper.rb +++ b/tests/helpers/bonafide_helper.rb @@ -17,58 +17,53 @@ class LeapTest raise exc end - def api_url(path) - api = property('api') - "https://%{domain}:%{port}#{path}" % { - :domain => api['domain'], - :port => api['port'] - } - end - # # attempts to create a user account via the API, # returning the user object if successful. # - def assert_create_user - user = SRP::User.new - url = api_url("/1/users.json") - + def assert_create_user(username=nil, auth=nil) + user = SRP::User.new(username) + url = api_url("/users.json") params = user.to_params - - if property('webapp.invite_required') - @invite_code = generate_invite_code - params['user[invite_code]'] = @invite_code + if auth + options = api_options(:auth => auth) + else + options = api_options + if property('webapp.invite_required') + @invite_code = generate_invite_code + params['user[invite_code]'] = @invite_code + end end - assert_post(url, params) do |body| + assert_post(url, params, options) do |body| assert response = JSON.parse(body), 'response should be JSON' assert response['ok'], "Creating a user should be successful, got #{response.inspect} instead." + user.ok = true + user.id = response['id'] end - user.ok = true return user end + # TODO: use the api for this instead. def generate_invite_code `cd /srv/leap/webapp/ && sudo -u leap-webapp RAILS_ENV=production bundle exec rake generate_invites[1]`.gsub(/\n/, "") end - # # attempts to authenticate user. if successful, # user object is updated with id and session token. # def assert_authenticate_user(user) - url = api_url("/1/sessions.json") + url = api_url("/sessions.json") session = SRP::Session.new(user) params = {'login' => user.username, 'A' => session.aa} - assert_post(url, params) do |response, body| + assert_post(url, params, api_options) do |body, response| cookie = response['Set-Cookie'].split(';').first assert(response = JSON.parse(body), 'response should be JSON') assert(session.bb = response["B"], 'response should include "B"') - url = api_url("/1/sessions/login.json") + url = api_url("/sessions/login.json") params = {'client_auth' => session.m, 'A' => session.aa} - options = {:headers => {'Cookie' => cookie}} - assert_put(url, params, options) do |body| + assert_put(url, params, api_options('Cookie' => cookie)) do |body| assert(response = JSON.parse(body), 'response should be JSON') assert(response['M2'], 'response should include M2') user.session_token = response['token'] @@ -83,16 +78,146 @@ class LeapTest # attempts to destroy a user account via the API. # def assert_delete_user(user) - if user && user.ok && user.id && user.session_token && !user.deleted - url = api_url("/1/users/#{user.id}.json") - options = {:headers => { - "Authorization" => "Token token=\"#{user.session_token}\"" - }} - params = { - :identities => 'destroy' + if user.is_a? String + assert_delete_user_by_login(user) + elsif user.is_a? SRP::User + assert_delete_srp_user(user) + end + end + + # + # returns true if the identity exists, uses monitor token auth + # + def identity_exists?(address) + url = api_url("/identities/#{URI.encode(address)}.json") + get(url, nil, api_options(:auth => :monitor)) do |body, response| + return response.code == "200" + end + end + + def upload_public_key(user_id, public_key) + url = api_url("/users/#{user_id}.json") + params = {"user[public_key]" => public_key} + assert_put(url, params, api_options(:auth => :monitor)) + end + + # + # return user document as a Hash. uses monitor token auth + # + def find_user_by_id(user_id) + url = api_url("/users/#{user_id}.json") + assert_get(url, nil, api_options(:auth => :monitor)) do |body| + return JSON.parse(body) + end + end + + # + # return user document as a Hash. uses monitor token auth + # NOTE: this relies on deprecated behavior of the API + # and will not work when multi-domain support is added. + # + def find_user_by_login(login) + url = api_url("/users/0.json?login=#{login}") + options = {:ok_codes => [200, 404]}.merge(api_options(:auth => :monitor)) + assert_get(url, nil, options) do |body, response| + if response.code == "200" + return JSON.parse(body) + else + return nil + end + end + end + + private + + def api_url(path) + unless path =~ /^\// + path = '/' + path + end + if property('testing.api_uri') + return property('testing.api_uri') + path + elsif property('api') + api = property('api') + return "https://%{domain}:%{port}/%{version}#{path}" % { + :domain => api['domain'], + :port => api['port'], + :version => api['version'] || 1 } + else + fail 'This node needs to have either testing.api_url or api.{domain,port} configured.' + end + end + + # + # produces an options hash used for api http requests. + # + # argument options hash gets added to "headers" + # of the http request. + # + # special :auth key in argument will expand to + # add api_token_auth header. + # + # if you want to try manually: + # + # export API_URI=`grep api_uri /etc/leap/hiera.yaml | cut -d\" -f2` + # export TOKEN=`grep monitor_auth_token /etc/leap/hiera.yaml | awk '{print $2}'` + # curl -H "Accept: application/json" -H "Token: $TOKEN" $API_URI + # + def api_options(options={}) + # note: must be :headers, not "headers" + hsh = { + :headers => { + "Accept" => "application/json" + } + } + if options[:auth] + hsh[:headers].merge!(api_token_auth(options.delete(:auth))) + end + hsh[:headers].merge!(options) + return hsh + end + + # + # add token authentication to a http request. + # + # returns a hash suitable for adding to the 'headers' option + # of an http function. + # + def api_token_auth(token) + if token.is_a?(Symbol) && property('testing') + if token == :monitor + token_str = property('testing.monitor_auth_token') + else + raise ArgumentError.new 'no such token' + end + else + token_str = token + end + {"Authorization" => "Token token=\"#{token_str}\""} + end + + # + # not actually used in any test, but useful when + # writing new tests. + # + def assert_delete_user_by_login(login_name) + user = find_user_by_login(login_name) + url = api_url("/users/#{user['id']}.json") + params = {:identities => 'destroy'} + delete(url, params, api_options(:auth => :monitor)) do |body, response, error| + assert error.nil?, "Error deleting user: #{error}" + assert response.code.to_i == 200, "Unable to delete user: HTTP response from API should have code 200, was #{response.code} #{error} #{body}" + assert(response = JSON.parse(body), 'Delete response should be JSON') + assert(response["success"], 'Deleting user should be a success') + end + end + + def assert_delete_srp_user(user) + if user && user.ok && user.id && user.session_token && !user.deleted + url = api_url("users/#{user.id}.json") + params = {:identities => 'destroy'} user.deleted = true - delete(url, params, options) do |body, response, error| + delete(url, params, api_options(:auth => user.session_token)) do |body, response, error| assert error.nil?, "Error deleting user: #{error}" assert response.code.to_i == 200, "Unable to delete user: HTTP response from API should have code 200, was #{response.code} #{error} #{body}" assert(response = JSON.parse(body), 'Delete response should be JSON') @@ -101,4 +226,5 @@ class LeapTest end end + end diff --git a/tests/helpers/couchdb_helper.rb b/tests/helpers/couchdb_helper.rb index 27dabfcb..b9085c1e 100644 --- a/tests/helpers/couchdb_helper.rb +++ b/tests/helpers/couchdb_helper.rb @@ -103,4 +103,40 @@ class LeapTest end end + def assert_destroy_user_db(user_id, options=nil) + db_name = "user-#{user_id}" + url = couchdb_url("/#{db_name}", options) + http_options = {:ok_codes => [200, 404]} # ignore missing dbs + assert_delete(url, nil, http_options) + end + + def assert_create_user_db(user_id, options=nil) + db_name = "user-#{user_id}" + url = couchdb_url("/#{db_name}", options) + http_options = {:ok_codes => [200, 404]} # ignore missing dbs + assert_put(url, nil, :format => :json) do |body| + assert response = JSON.parse(body), "PUT response should be JSON" + assert response["ok"], "PUT response should be OK" + end + end + + # + # returns true if the per-user db created by soledad-server exists. + # + def user_db_exists?(user_id, options=nil) + db_name = "user-#{user_id}" + url = couchdb_url("/#{db_name}", options) + get(url) do |body, response, error| + if response.nil? + fail "could not query couchdb #{url}: #{error}\n#{body}" + elsif response.code.to_i == 200 + return true + elsif response.code.to_i == 404 + return false + else + fail ["could not query couchdb #{url}: expected response code 200 or 404, but got #{response.code}.", error, body].compact.join("\n") + end + end + end + end \ No newline at end of file diff --git a/tests/helpers/http_helper.rb b/tests/helpers/http_helper.rb index 2fcdc910..0d0bb7d5 100644 --- a/tests/helpers/http_helper.rb +++ b/tests/helpers/http_helper.rb @@ -81,20 +81,31 @@ class LeapTest # # calls http_send, yielding results if successful or failing with - # descriptive infor otherwise. + # descriptive info otherwise. + # + # options: + # - error_msg: custom error message to display. + # - ok_codes: in addition to 2xx, codes in this array will not produce an error. # def assert_http_send(method, url, params=nil, options=nil, &block) options ||= {} error_msg = options[:error_msg] || (url.respond_to?(:memo) ? url.memo : nil) http_send(method, url, params, options) do |body, response, error| - ok = response && response.code.to_i >= 200 && response.code.to_i < 300 - if body && ok - if block - yield(body) if block.arity == 1 - yield(response, body) if block.arity == 2 + if response + code = response.code.to_i + ok = code >= 200 && code < 300 + if options[:ok_codes] + ok ||= options[:ok_codes].include?(code) + end + if ok + if block + yield(body) if block.arity == 1 + yield(body, response) if block.arity == 2 + yield(body, response, error) if block.arity == 3 + end + else + fail ["Expected success code from #{method} #{url}, but got #{response.code} instead.", error_msg, body].compact.join("\n") end - elsif response && !ok - fail ["Expected a 200 status code from #{method} #{url}, but got #{response.code} instead.", error_msg, body].compact.join("\n") else fail ["Expected a response from #{method} #{url}, but got \"#{error}\" instead.", error_msg, body].compact.join("\n"), error end diff --git a/tests/helpers/smtp_helper.rb b/tests/helpers/smtp_helper.rb new file mode 100644 index 00000000..ea7fb9fa --- /dev/null +++ b/tests/helpers/smtp_helper.rb @@ -0,0 +1,45 @@ +require 'net/smtp' + +class LeapTest + + TEST_EMAIL_USER = "test_user_email" + TEST_BAD_USER = "test_user_bad" + + MSG_BODY = %(Since it seems that any heart which beats for freedom has the right only to a +lump of lead, I too claim my share. If you let me live, I shall never stop +crying for revenge and I shall avenge my brothers. I have finished. If you are +not cowards, kill me! + +--Louise Michel) + + def send_email(recipient, options={}) + sender = options[:sender] || recipient + helo_domain = property('domain.full_suffix') + headers = { + "Date" => Time.now.utc, + "From" => sender, + "To" => recipient, + "Subject" => "Test Message", + "X-LEAP-TEST" => "true" + }.merge(options[:headers]||{}) + message = [] + headers.each do |key, value| + message << "#{key}: #{value}" + end + message << "" + message << MSG_BODY + Net::SMTP.start('localhost', 25, helo_domain) do |smtp| + smtp.send_message message.join("\n"), recipient, sender + end + end + + def assert_send_email(recipient, options={}) + begin + send_email(recipient, options) + rescue IOError, Net::OpenTimeout, + Net::ReadTimeout, Net::SMTPError => e + fail "Could not send mail to #{recipient} (#{e})" + end + end + +end \ No newline at end of file diff --git a/tests/helpers/srp_helper.rb b/tests/helpers/srp_helper.rb index 5d30b459..b30fa768 100644 --- a/tests/helpers/srp_helper.rb +++ b/tests/helpers/srp_helper.rb @@ -138,8 +138,8 @@ d15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e5 attr_accessor :username, :password, :salt, :verifier, :id, :session_token, :ok, :deleted - def initialize - @username = "test_user_" + SecureRandom.urlsafe_base64(10).downcase.gsub(/[_-]/, '') + def initialize(username=nil) + @username = username || "tmp_user_" + SecureRandom.urlsafe_base64(10).downcase.gsub(/[_-]/, '') @password = "password_" + SecureRandom.urlsafe_base64(10) @salt = bigrand(4).hex @verifier = modpow(GENERATOR, private_key) diff --git a/tests/order.rb b/tests/order.rb index 4468686f..14aad9be 100644 --- a/tests/order.rb +++ b/tests/order.rb @@ -9,11 +9,14 @@ class LeapCli::Config::Node # def test_dependencies dependents = LeapCli::Config::ObjectList.new - unless services.include?('couchdb') - if services.include?('webapp') || services.include?('mx') || services.include?('soledad') + + # webapp, mx, and soledad depend on couchdb nodes + if services.include?('webapp') || services.include?('mx') || services.include?('soledad') + if !services.include?('couchdb') dependents.merge! nodes_like_me[:services => 'couchdb'] end end + dependents.keys.delete_if {|name| self.name == name} end end \ No newline at end of file diff --git a/tests/white-box/couchdb.rb b/tests/white-box/couchdb.rb index da226cc9..859b4745 100644 --- a/tests/white-box/couchdb.rb +++ b/tests/white-box/couchdb.rb @@ -127,6 +127,33 @@ class CouchDB < LeapTest pass end + # + # This is not really a "test", just an attempt to make sure that + # the mx tests that fire off dummy emails don't fill up the + # storage db. + # + # mx tests can't run this because they don't have access to + # the storage db. + # + # This "test" is responsible for both creating the db if it does not + # exist, and destroying if it does. + # + # Yes, this is super hacky. Properly, we should add something to + # the soledad api to support create/delete of user storage dbs. + # + def test_99_Delete_mail_storage_used_in_mx_tests + user = find_user_by_login(TEST_EMAIL_USER) + if user + if user_db_exists?(user["id"]) + # keep the test email db from filling up: + assert_destroy_user_db(user["id"], :username => 'admin') + end + # either way, make sure we leave a db for the mx tests: + assert_create_user_db(user["id"], :username => 'admin') + end + # no 'pass' at the end, since this is not a real test. + end + private def multimaster? diff --git a/tests/white-box/mx.rb b/tests/white-box/mx.rb index 57ec9117..6c0982ce 100644 --- a/tests/white-box/mx.rb +++ b/tests/white-box/mx.rb @@ -1,9 +1,11 @@ raise SkipTest unless service?(:mx) require 'json' +require 'net/smtp' class Mx < LeapTest depends_on "Network" + depends_on "Webapp" if service?(:webapp) def setup end @@ -11,7 +13,7 @@ class Mx < LeapTest def test_01_Can_contact_couchdb? dbs = ["identities"] dbs.each do |db_name| - couchdb_urls("/"+db_name, url_options).each do |url| + couchdb_urls("/"+db_name, couch_url_options).each do |url| assert_get(url) do |body| assert response = JSON.parse(body) assert_equal db_name, response['db_name'] @@ -23,7 +25,7 @@ class Mx < LeapTest def test_02_Can_contact_couchdb_via_haproxy? if property('haproxy.couch') - url = couchdb_url_via_haproxy("", url_options) + url = couchdb_url_via_haproxy("", couch_url_options) assert_get(url) do |body| assert_match /"couchdb":"Welcome"/, body, "Request to #{url} should return couchdb welcome message." end @@ -36,7 +38,7 @@ class Mx < LeapTest # using the by_address view for that same document again. # def test_03_Can_query_identities_db? - assert_get(couchdb_url("/identities", url_options)) do |body| + assert_get(couchdb_url("/identities", couch_url_options)) do |body| assert response = JSON.parse(body) doc_count = response['doc_count'].to_i if doc_count <= 1 @@ -46,7 +48,7 @@ class Mx < LeapTest # try five times to get a valid doc for i in 1..5 offset = rand(doc_count) # pick a random document - count_url = couchdb_url("/identities/_all_docs?include_docs=true&limit=1&skip=#{offset}", url_options) + count_url = couchdb_url("/identities/_all_docs?include_docs=true&limit=1&skip=#{offset}", couch_url_options) assert_get(count_url) do |body| assert response = JSON.parse(body) record = response['rows'].first @@ -57,7 +59,7 @@ class Mx < LeapTest assert address, "Identity document #{record['id']} is missing an address field. #{record['doc'].inspect}" url_base = %(/identities/_design/Identity/_view/by_address) params = %(?include_docs=true&reduce=false&startkey="#{address}"&endkey="#{address}") - assert_get(couchdb_url(url_base+params, url_options)) do |body| + assert_get(couchdb_url(url_base+params, couch_url_options)) do |body| assert response = JSON.parse(body) assert record = response['rows'].first assert_equal address, record['doc']['address'] @@ -71,7 +73,7 @@ class Mx < LeapTest end end - def test_03_Are_MX_daemons_running? + def test_04_Are_MX_daemons_running? assert_running '.*/usr/bin/twistd.*mx.tac' assert_running '^/usr/lib/postfix/master$' assert_running '^/usr/sbin/postfwd' @@ -89,13 +91,96 @@ class Mx < LeapTest pass end + # + # The email sent by this test might get bounced back. + # In this case, the test will pass, but the bounce message will + # get sent to root, so the sysadmin will still figure out pretty + # quickly that something is wrong. + # + def test_05_Can_deliver_email? + addr = [TEST_EMAIL_USER, property('domain.full_suffix')].join('@') + bad_addr = [TEST_BAD_USER, property('domain.full_suffix')].join('@') + + assert !identity_exists?(bad_addr), "the address #{bad_addr} must not exist." + if !identity_exists?(addr) + user = assert_create_user(TEST_EMAIL_USER, :monitor) + upload_public_key(user.id, TEST_EMAIL_PUBLIC_KEY) + end + assert identity_exists?(addr), "The identity #{addr} should have been created, but it doesn't exist yet." + assert_send_email(addr) + assert_raises(Net::SMTPError) do + send_email(bad_addr) + end + pass + end + private - def url_options + def couch_url_options { :username => property('couchdb_leap_mx_user.username'), :password => property('couchdb_leap_mx_user.password') } end + TEST_EMAIL_PUBLIC_KEY=< property('couchdb_webapp_user.username'), - :password => property('couchdb_webapp_user.password') + :username => property('webapp.couchdb_webapp_user.username'), + :password => property('webapp.couchdb_webapp_user.password') } end @@ -131,18 +131,4 @@ class Webapp < LeapTest return end - # - # I tried, but couldn't get this working: - # # - # # get an CSRF authenticity token - # # - # url = api_url("/") - # csrf_token = nil - # assert_get(url) do |body| - # lines = body.split("\n").grep(/csrf-token/) - # assert lines.any?, 'failed to find csrf-token' - # csrf_token = lines.first.split('"')[1] - # assert csrf_token, 'failed to find csrf-token' - # end - end -- cgit v1.2.3