summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/helpers/bonafide_helper.rb99
-rw-r--r--tests/helpers/http_helper.rb4
-rw-r--r--tests/helpers/os_helper.rb8
-rwxr-xr-xtests/helpers/soledad_sync.py78
-rw-r--r--tests/helpers/srp_helper.rb8
-rw-r--r--tests/white-box/couchdb.rb2
-rw-r--r--tests/white-box/webapp.rb103
7 files changed, 237 insertions, 65 deletions
diff --git a/tests/helpers/bonafide_helper.rb b/tests/helpers/bonafide_helper.rb
new file mode 100644
index 00000000..9b26eaaf
--- /dev/null
+++ b/tests/helpers/bonafide_helper.rb
@@ -0,0 +1,99 @@
+#
+# helper for the communication with the provider API for creating, authenticating, and deleting accounts.
+#
+
+class LeapTest
+
+ def assert_tmp_user
+ user = assert_create_user
+ assert_authenticate_user(user)
+ yield user if block_given?
+ assert_delete_user(user)
+ rescue StandardError, MiniTest::Assertion => exc
+ begin
+ assert_delete_user(user)
+ rescue
+ end
+ 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")
+ assert_post(url, user.to_params) do |body|
+ assert response = JSON.parse(body), 'response should be JSON'
+ assert response['ok'], "Creating a user should be successful, got #{response.inspect} instead."
+ end
+ user.ok = true
+ return user
+ 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")
+ session = SRP::Session.new(user)
+ params = {'login' => user.username, 'A' => session.aa}
+ assert_post(url, params) do |response, body|
+ 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")
+ params = {'client_auth' => session.m, 'A' => session.aa}
+ options = {:headers => {'Cookie' => cookie}}
+ assert_put(url, params, options) do |body|
+ assert(response = JSON.parse(body), 'response should be JSON')
+ assert(response['M2'], 'response should include M2')
+ user.session_token = response['token']
+ user.id = response['id']
+ assert(user.session_token, 'response should include token')
+ assert(user.id, 'response should include user id')
+ end
+ end
+ end
+
+ #
+ # 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'
+ }
+ user.deleted = true
+ delete(url, params, options) 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
+ domain = property('domain.full_suffix')
+ identities_url = couchdb_url("/identities/_design/Identity/_view/by_address?key=%22#{user.username}@#{domain}%22")
+ get(identities_url) do |body, response, error|
+ assert error.nil?, "Error checking identities db: #{error}"
+ assert response.code.to_i == 200, "Unable to check that user identity was deleted: HTTP response from API should have code 200, was #{response.code} #{error} #{body}"
+ assert(response = JSON.parse(body), 'Couch response should be JSON')
+ assert response['rows'].empty?, "Identity should have been deleted for test user #{user.username} (id #{user.id}), but was not! Response was: #{body}."
+ end
+ end
+ end
+
+end
diff --git a/tests/helpers/http_helper.rb b/tests/helpers/http_helper.rb
index c941ef63..0b13b754 100644
--- a/tests/helpers/http_helper.rb
+++ b/tests/helpers/http_helper.rb
@@ -93,9 +93,9 @@ class LeapTest
yield(response, body) if block.arity == 2
end
elsif response
- fail ["Expected a 200 status code from #{url}, but got #{response.code} instead.", error_msg, body].compact.join("\n")
+ 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 #{url}, but got \"#{error}\" instead.", error_msg, body].compact.join("\n"), error
+ fail ["Expected a response from #{method} #{url}, but got \"#{error}\" instead.", error_msg, body].compact.join("\n"), error
end
end
end
diff --git a/tests/helpers/os_helper.rb b/tests/helpers/os_helper.rb
index 529e899f..aad67dda 100644
--- a/tests/helpers/os_helper.rb
+++ b/tests/helpers/os_helper.rb
@@ -17,8 +17,12 @@ class LeapTest
}.compact
end
- def assert_running(process)
- assert pgrep(process).any?, "No running process for #{process}"
+ def assert_running(process, options={})
+ processes = pgrep(process)
+ assert processes.any?, "No running process for #{process}"
+ if options[:single]
+ assert processes.length == 1, "More than one process for #{process}"
+ end
end
#
diff --git a/tests/helpers/soledad_sync.py b/tests/helpers/soledad_sync.py
new file mode 100755
index 00000000..2fb865fc
--- /dev/null
+++ b/tests/helpers/soledad_sync.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+
+#
+# Test Soledad sync
+#
+# This script performs a slightly modified U1DB sync to the Soledad server and
+# returns whether that sync was successful or not.
+#
+# It takes three arguments:
+#
+# uuid -- uuid of the user to sync
+# token -- a valid session token
+# server -- the url of the soledad server we should connect to
+#
+# For example:
+#
+# soledad_sync.py f6bef0586fcfdb8705e26a58f2d9e580 uYO-4ucEJFksJ6afjmcYwIyap2vW7bv6uLxk0w_RfCc https://199.119.112.9:2323/user-f6bef0586fcfdb8705e26a58f2d9e580
+#
+
+import os
+import sys
+import traceback
+import tempfile
+import shutil
+import u1db
+
+from u1db.remote.http_target import HTTPSyncTarget
+
+#
+# monkey patch U1DB's HTTPSyncTarget to perform token based auth
+#
+
+def set_token_credentials(self, uuid, token):
+ self._creds = {'token': (uuid, token)}
+
+def _sign_request(self, method, url_query, params):
+ uuid, token = self._creds['token']
+ auth = '%s:%s' % (uuid, token)
+ return [('Authorization', 'Token %s' % auth.encode('base64')[:-1])]
+
+HTTPSyncTarget.set_token_credentials = set_token_credentials
+HTTPSyncTarget._sign_request = _sign_request
+
+#
+# Create a temporary local u1db replica and attempt to sync to it.
+# Returns a failure message if something went wrong.
+#
+
+def soledad_sync(uuid, token, server):
+ tempdir = tempfile.mkdtemp()
+ try:
+ db = u1db.open(os.path.join(tempdir, '%s.db' % uuid), True)
+ creds = {'token': {'uuid': uuid, 'token': token}}
+ db.sync(server, creds=creds, autocreate=False)
+ finally:
+ shutil.rmtree(tempdir)
+
+#
+# exit codes:
+#
+# 0 - OK
+# 1 - WARNING
+# 2 - ERROR
+#
+
+if __name__ == '__main__':
+ try:
+ uuid, token, server = sys.argv[1:]
+ result = soledad_sync(uuid, token, server)
+ if result is None:
+ exit(0)
+ else:
+ print(result)
+ exit(1)
+ except Exception as exc:
+ print(exc.message or str(exc))
+ traceback.print_exc(file=sys.stdout)
+ exit(2)
diff --git a/tests/helpers/srp_helper.rb b/tests/helpers/srp_helper.rb
index 9f4d7f5b..5d30b459 100644
--- a/tests/helpers/srp_helper.rb
+++ b/tests/helpers/srp_helper.rb
@@ -6,6 +6,7 @@
require 'digest'
require 'openssl'
require 'securerandom'
+require 'base64'
module SRP
@@ -135,16 +136,15 @@ d15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e5
class User
include SRP::Util
- attr_accessor :username
- attr_accessor :password
- attr_accessor :salt
- attr_accessor :verifier
+ attr_accessor :username, :password, :salt, :verifier, :id, :session_token, :ok, :deleted
def initialize
@username = "test_user_" + SecureRandom.urlsafe_base64(10).downcase.gsub(/[_-]/, '')
@password = "password_" + SecureRandom.urlsafe_base64(10)
@salt = bigrand(4).hex
@verifier = modpow(GENERATOR, private_key)
+ @ok = false
+ @deleted = false
end
def private_key
diff --git a/tests/white-box/couchdb.rb b/tests/white-box/couchdb.rb
index 2788f4f7..450c4201 100644
--- a/tests/white-box/couchdb.rb
+++ b/tests/white-box/couchdb.rb
@@ -9,7 +9,7 @@ class CouchDB < LeapTest
end
def test_00_Are_daemons_running?
- assert_running 'tapicero'
+ assert_running '^tapicero', :single => true
if multimaster?
assert_running 'bin/beam'
assert_running 'bin/epmd'
diff --git a/tests/white-box/webapp.rb b/tests/white-box/webapp.rb
index 2aa87403..9f104899 100644
--- a/tests/white-box/webapp.rb
+++ b/tests/white-box/webapp.rb
@@ -41,63 +41,26 @@ class Webapp < LeapTest
pass
end
- def test_05_Can_create_user?
- @@user = nil
- user = SRP::User.new
- url = api_url("/1/users.json")
- assert_post(url, user.to_params) do |body|
- assert response = JSON.parse(body), 'response should be JSON'
- assert response['ok'], 'creating a user should be successful'
- end
- @@user = user
+ def test_05_Can_create_and_authenticate_and_delete_user_via_API?
+ assert_tmp_user
pass
end
- def test_06_Can_authenticate?
- @@user_id = nil
- @@session_token = nil
- if @@user.nil?
- skip "Depends on user creation"
- else
- url = api_url("/1/sessions.json")
- session = SRP::Session.new(@@user)
- params = {'login' => @@user.username, 'A' => session.aa}
- assert_post(url, params) do |response, body|
- cookie = response['Set-Cookie'].split(';').first
- assert(response = JSON.parse(body), 'response should be JSON')
- assert(bb = response["B"])
- session.bb = bb
- url = api_url("/1/sessions/login.json")
- params = {'client_auth' => session.m, 'A' => session.aa}
- options = {:headers => {'Cookie' => cookie}}
- assert_put(url, params, options) do |body|
- assert(response = JSON.parse(body), 'response should be JSON')
- assert(response['M2'], 'response should include M2')
- assert(@@session_token = response['token'], 'response should include token')
- assert(@@user_id = response['id'], 'response should include user id')
- end
- end
- pass
- end
- end
-
- def test_07_Can_delete_user?
- if @@user_id.nil? || @@session_token.nil?
- skip "Depends on authentication"
- else
- url = api_url("/1/users/#{@@user_id}.json")
- options = {:headers => {
- "Authorization" => "Token token=\"#{@@session_token}\""
- }}
- delete(url, {}, options) do |body, response, error|
- if response.code.to_i != 200
- skip "It appears the web api is too old to support deleting users"
- else
- assert(response = JSON.parse(body), 'response should be JSON')
- assert(response["success"], 'delete should be a success')
+ def test_06_Can_sync_Soledad?
+ soledad_config = property('definition_files.soledad_service')
+ if soledad_config && !soledad_config.empty?
+ soledad_server = pick_soledad_server(soledad_config)
+ if soledad_server
+ assert_tmp_user do |user|
+ assert_user_db_exists(user)
+ command = File.expand_path "../../helpers/soledad_sync.py", __FILE__
+ soledad_url = "https://#{soledad_server}/user-#{user.id}"
+ assert_run "#{command} #{user.id} #{user.session_token} #{soledad_url}"
pass
end
end
+ else
+ skip 'No soledad service configuration'
end
end
@@ -110,11 +73,39 @@ class Webapp < LeapTest
}
end
- def api_url(path)
- "https://%{domain}:%{port}#{path}" % {
- :domain => property('api.domain'),
- :port => property('api.port')
- }
+ #
+ # pick a random soledad server.
+ # I am not sure why, but using IP address directly does not work.
+ #
+ def pick_soledad_server(soledad_config_json_str)
+ soledad_config = JSON.parse(soledad_config_json_str)
+ host_name = soledad_config['hosts'].keys.shuffle.first
+ if host_name
+ hostname = soledad_config['hosts'][host_name]['hostname']
+ port = soledad_config['hosts'][host_name]['port']
+ return "#{hostname}:#{port}"
+ else
+ return nil
+ end
+ end
+
+ #
+ # returns true if the per-user db created by tapicero exists.
+ # we try three times, and give up after that.
+ #
+ def assert_user_db_exists(user)
+ last_body, last_response, last_error = nil
+ 3.times do
+ sleep 0.1
+ get(couchdb_url("/user-#{user.id}/_design/docs")) do |body, response, error|
+ last_body, last_response, last_error = body, response, error
+ if response.code.to_i == 200
+ return
+ end
+ end
+ sleep 0.2
+ end
+ assert false, "Could not find user db for test user #{user.username}\nuuid=#{user.id}\nHTTP #{last_response.code} #{last_error} #{last_body}"
end
#