From c20aa4f8c35a4cba982de92105da2566ecdfa1ae Mon Sep 17 00:00:00 2001 From: elijah Date: Sun, 22 Jun 2014 13:42:04 -0700 Subject: run_tests: allow for https in assert_get() --- tests/white-box/webapp.rb | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tests') diff --git a/tests/white-box/webapp.rb b/tests/white-box/webapp.rb index 142ac2de..05b86a41 100644 --- a/tests/white-box/webapp.rb +++ b/tests/white-box/webapp.rb @@ -60,4 +60,13 @@ class Webapp < LeapTest pass end + # + # this is technically a black-box test. so, move this when we have support + # for black box tests. + # + def test_04_Can_access_webapp? + assert_get('https://' + $node['webapp']['domain'] + '/') + pass + end + end -- cgit v1.2.3 From 10c76ac1cfa4e94375b456266e4113a4313abe96 Mon Sep 17 00:00:00 2001 From: elijah Date: Mon, 23 Jun 2014 02:40:21 -0700 Subject: tests: fixed problem with showing couchdb password in process table, and adding warnings for when ACL is not being respected (which is currently always). closes #5445 --- tests/white-box/couchdb.rb | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) (limited to 'tests') diff --git a/tests/white-box/couchdb.rb b/tests/white-box/couchdb.rb index 9d5da94f..8b9789bd 100644 --- a/tests/white-box/couchdb.rb +++ b/tests/white-box/couchdb.rb @@ -33,7 +33,7 @@ class CouchDB < LeapTest neighbors = assert_property('couch.bigcouch.neighbors') neighbors << assert_property('domain.full') neighbors.sort! - assert_get(url) do |body| + assert_get(url, nil, http_basic_auth) do |body| response = JSON.parse(body) nodes_in_db = response['rows'].collect{|row| row['id'].sub(/^bigcouch@/, '')}.sort assert_equal neighbors, nodes_in_db, "The couchdb replication node list is wrong (/nodes/_all_docs)" @@ -49,7 +49,7 @@ class CouchDB < LeapTest # def test_03_Are_configured_nodes_online? url = couchdb_url("/_membership") - assert_get(url) do |body| + assert_get(url, nil, http_basic_auth) do |body| response = JSON.parse(body) nodes_configured_but_not_available = response['cluster_nodes'] - response['all_nodes'] nodes_available_but_not_configured = response['all_nodes'] - response['cluster_nodes'] @@ -68,7 +68,7 @@ class CouchDB < LeapTest def test_04_Do_ACL_users_exist? acl_users = ['_design/_auth', 'leap_mx', 'nickserver', 'soledad', 'tapicero', 'webapp'] url = couchdb_backend_url("/_users/_all_docs") - assert_get(url) do |body| + assert_get(url, nil, http_basic_auth) do |body| response = JSON.parse(body) assert_equal 6, response['total_rows'] actual_users = response['rows'].map{|row| row['id'].sub(/^org.couchdb.user:/, '') } @@ -88,6 +88,23 @@ class CouchDB < LeapTest pass end + # + # for now, this just prints warnings, since we are failing these tests. + # + def test_06_Is_ACL_enforced? + ok = assert_auth_fail( + couchdb_url('/users/_all_docs'), + {:limit => 1}, + http_basic_auth('leap_mx') + ) + ok = assert_auth_fail( + couchdb_url('/users/_all_docs'), + {:limit => 1}, + {} + ) && ok + pass if ok + end + private def couchdb_url(path="", port=nil) @@ -95,15 +112,17 @@ class CouchDB < LeapTest assert_property 'couch.port' $node['couch']['port'] end - @password ||= begin - assert_property 'couch.users.admin.password' - $node['couch']['users']['admin']['password'] - end - "http://admin:#{@password}@localhost:#{port || @port}#{path}" + "http://localhost:#{port || @port}#{path}" end def couchdb_backend_url(path="") couchdb_url(path, "5986") # TODO: admin port is hardcoded for now but should be configurable. end + def http_basic_auth(username='admin') + assert_property 'couch.users.' + username + password = $node['couch']['users'][username]['password'] + {:username => username, :password => password} + end + end -- cgit v1.2.3 From edf1306a418203df297d034544d51f5cdcd053c7 Mon Sep 17 00:00:00 2001 From: elijah Date: Wed, 25 Jun 2014 17:21:49 -0700 Subject: run_tests: clean up assert_get() --- tests/white-box/couchdb.rb | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) (limited to 'tests') diff --git a/tests/white-box/couchdb.rb b/tests/white-box/couchdb.rb index 8b9789bd..a6ad0f6a 100644 --- a/tests/white-box/couchdb.rb +++ b/tests/white-box/couchdb.rb @@ -33,7 +33,7 @@ class CouchDB < LeapTest neighbors = assert_property('couch.bigcouch.neighbors') neighbors << assert_property('domain.full') neighbors.sort! - assert_get(url, nil, http_basic_auth) do |body| + assert_get(url) do |body| response = JSON.parse(body) nodes_in_db = response['rows'].collect{|row| row['id'].sub(/^bigcouch@/, '')}.sort assert_equal neighbors, nodes_in_db, "The couchdb replication node list is wrong (/nodes/_all_docs)" @@ -48,8 +48,8 @@ class CouchDB < LeapTest # this seems backward to me, so it might be the other way around. # def test_03_Are_configured_nodes_online? - url = couchdb_url("/_membership") - assert_get(url, nil, http_basic_auth) do |body| + url = couchdb_url("/_membership", :user => 'admin') + assert_get(url) do |body| response = JSON.parse(body) nodes_configured_but_not_available = response['cluster_nodes'] - response['all_nodes'] nodes_available_but_not_configured = response['all_nodes'] - response['cluster_nodes'] @@ -68,7 +68,7 @@ class CouchDB < LeapTest def test_04_Do_ACL_users_exist? acl_users = ['_design/_auth', 'leap_mx', 'nickserver', 'soledad', 'tapicero', 'webapp'] url = couchdb_backend_url("/_users/_all_docs") - assert_get(url, nil, http_basic_auth) do |body| + assert_get(url) do |body| response = JSON.parse(body) assert_equal 6, response['total_rows'] actual_users = response['rows'].map{|row| row['id'].sub(/^org.couchdb.user:/, '') } @@ -93,36 +93,40 @@ class CouchDB < LeapTest # def test_06_Is_ACL_enforced? ok = assert_auth_fail( - couchdb_url('/users/_all_docs'), - {:limit => 1}, - http_basic_auth('leap_mx') + couchdb_url('/users/_all_docs', :user => 'leap_mx'), + {:limit => 1} ) ok = assert_auth_fail( - couchdb_url('/users/_all_docs'), - {:limit => 1}, - {} + couchdb_url('/users/_all_docs', :user => 'leap_mx'), + {:limit => 1} ) && ok pass if ok end + def test_07_What? + pass + end + private - def couchdb_url(path="", port=nil) + def couchdb_url(path="", options=nil) + options||={} @port ||= begin assert_property 'couch.port' $node['couch']['port'] end - "http://localhost:#{port || @port}#{path}" + url = 'http://' + if options[:user] + assert_property 'couch.users.' + options[:user] + password = $node['couch']['users'][options[:user]]['password'] + url += "%s:%s@" % [options[:user], password] + end + url += "localhost:#{options[:port] || @port}#{path}" + url end def couchdb_backend_url(path="") - couchdb_url(path, "5986") # TODO: admin port is hardcoded for now but should be configurable. - end - - def http_basic_auth(username='admin') - assert_property 'couch.users.' + username - password = $node['couch']['users'][username]['password'] - {:username => username, :password => password} + couchdb_url(path, :port => "5986") # TODO: admin port is hardcoded for now but should be configurable. end end -- cgit v1.2.3 From 6cd7beed954e594110f04dbd0637cb17168ba4dd Mon Sep 17 00:00:00 2001 From: elijah Date: Wed, 25 Jun 2014 18:07:13 -0700 Subject: fix couchdb tests for plain couch --- tests/white-box/couchdb.rb | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'tests') diff --git a/tests/white-box/couchdb.rb b/tests/white-box/couchdb.rb index a6ad0f6a..58a24731 100644 --- a/tests/white-box/couchdb.rb +++ b/tests/white-box/couchdb.rb @@ -10,8 +10,10 @@ class CouchDB < LeapTest def test_00_Are_daemons_running? assert_running 'tapicero' - assert_running 'bin/beam' - assert_running 'bin/epmd' + if multimaster? + assert_running 'bin/beam' + assert_running 'bin/epmd' + end pass end @@ -29,6 +31,7 @@ class CouchDB < LeapTest # compare the configured nodes to the nodes that are actually listed in bigcouch # def test_02_Is_cluster_membership_ok? + skip "not a multimaster node" unless multimater? url = couchdb_backend_url("/nodes/_all_docs") neighbors = assert_property('couch.bigcouch.neighbors') neighbors << assert_property('domain.full') @@ -48,6 +51,7 @@ class CouchDB < LeapTest # this seems backward to me, so it might be the other way around. # def test_03_Are_configured_nodes_online? + skip "not a multimaster node" unless multimater? url = couchdb_url("/_membership", :user => 'admin') assert_get(url) do |body| response = JSON.parse(body) @@ -66,11 +70,11 @@ class CouchDB < LeapTest end def test_04_Do_ACL_users_exist? - acl_users = ['_design/_auth', 'leap_mx', 'nickserver', 'soledad', 'tapicero', 'webapp'] + acl_users = ['_design/_auth', 'leap_mx', 'nickserver', 'soledad', 'tapicero', 'webapp', 'replication'] url = couchdb_backend_url("/_users/_all_docs") assert_get(url) do |body| response = JSON.parse(body) - assert_equal 6, response['total_rows'] + assert_equal acl_users.count, response['total_rows'] actual_users = response['rows'].map{|row| row['id'].sub(/^org.couchdb.user:/, '') } assert_equal acl_users.sort, actual_users.sort end @@ -126,7 +130,16 @@ class CouchDB < LeapTest end def couchdb_backend_url(path="") - couchdb_url(path, :port => "5986") # TODO: admin port is hardcoded for now but should be configurable. + # TODO: admin port is hardcoded for now but should be configurable. + couchdb_url(path, multimaster? && "5986") + end + + def multimaster? + mode == "multimaster" + end + + def mode + assert_property('couch.mode') end end -- cgit v1.2.3 From 8d5c14b26b6f95285d9ed2b17c61d18d5de005e6 Mon Sep 17 00:00:00 2001 From: elijah Date: Wed, 25 Jun 2014 23:54:16 -0700 Subject: fix tests for new 0.6 format --- tests/white-box/couchdb.rb | 4 ++-- tests/white-box/network.rb | 33 +++++++++++++++------------------ 2 files changed, 17 insertions(+), 20 deletions(-) (limited to 'tests') diff --git a/tests/white-box/couchdb.rb b/tests/white-box/couchdb.rb index 58a24731..74bd47bf 100644 --- a/tests/white-box/couchdb.rb +++ b/tests/white-box/couchdb.rb @@ -31,7 +31,7 @@ class CouchDB < LeapTest # compare the configured nodes to the nodes that are actually listed in bigcouch # def test_02_Is_cluster_membership_ok? - skip "not a multimaster node" unless multimater? + return unless multimaster? url = couchdb_backend_url("/nodes/_all_docs") neighbors = assert_property('couch.bigcouch.neighbors') neighbors << assert_property('domain.full') @@ -51,7 +51,7 @@ class CouchDB < LeapTest # this seems backward to me, so it might be the other way around. # def test_03_Are_configured_nodes_online? - skip "not a multimaster node" unless multimater? + return unless multimaster? url = couchdb_url("/_membership", :user => 'admin') assert_get(url) do |body| response = JSON.parse(body) diff --git a/tests/white-box/network.rb b/tests/white-box/network.rb index e0b0339d..118861a7 100644 --- a/tests/white-box/network.rb +++ b/tests/white-box/network.rb @@ -28,29 +28,26 @@ class Network < LeapTest def test_02_Is_stunnel_running? if $node['stunnel'] good_stunnel_pids = [] - $node['stunnel'].each do |stunnel_type, stunnel_configs| - if stunnel_type =~ /_clients?$/ - stunnel_configs.each do |stunnel_name, stunnel_conf| - config_file_name = "/etc/stunnel/#{stunnel_name}.conf" - processes = pgrep(config_file_name) - assert_equal 6, processes.length, "There should be six stunnel processes running for `#{config_file_name}`" - good_stunnel_pids += processes.map{|ps| ps[:pid]} - assert port = stunnel_conf['accept_port'], 'Field `accept_port` must be present in `stunnel` property.' - assert_tcp_socket('localhost', port) - end - elsif stunnel_type =~ /_server$/ - config_file_name = "/etc/stunnel/#{stunnel_type}.conf" + $node['stunnel']['clients'].each do |stunnel_type, stunnel_configs| + stunnel_configs.each do |stunnel_name, stunnel_conf| + config_file_name = "/etc/stunnel/#{stunnel_name}.conf" processes = pgrep(config_file_name) assert_equal 6, processes.length, "There should be six stunnel processes running for `#{config_file_name}`" good_stunnel_pids += processes.map{|ps| ps[:pid]} - assert accept = stunnel_configs['accept'], "Field `accept` must be present in property `stunnel.#{stunnel_type}`" - assert_tcp_socket('localhost', accept) - assert connect = stunnel_configs['connect'], "Field `connect` must be present in property `stunnel.#{stunnel_type}`" - assert_tcp_socket(*connect.split(':')) - else - skip "Unknown stunnel type `#{stunnel_type}`" + assert port = stunnel_conf['accept_port'], 'Field `accept_port` must be present in `stunnel` property.' + assert_tcp_socket('localhost', port) end end + $node['stunnel']['servers'].each do |stunnel_name, stunnel_conf| + config_file_name = "/etc/stunnel/#{stunnel_name}.conf" + processes = pgrep(config_file_name) + assert_equal 6, processes.length, "There should be six stunnel processes running for `#{config_file_name}`" + good_stunnel_pids += processes.map{|ps| ps[:pid]} + assert accept_port = stunnel_conf['accept_port'], "Field `accept` must be present in property `stunnel.servers.#{stunnel_name}`" + assert_tcp_socket('localhost', accept_port) + assert connect_port = stunnel_conf['connect_port'], "Field `connect` must be present in property `stunnel.servers.#{stunnel_name}`" + assert_tcp_socket('localhost', connect_port) + end all_stunnel_pids = pgrep('/usr/bin/stunnel').collect{|process| process[:pid]}.uniq assert_equal good_stunnel_pids.sort, all_stunnel_pids.sort, "There should not be any extra stunnel processes that are not configured in /etc/stunnel" pass -- cgit v1.2.3 From e97d0195fff2286d35c18866167b74cc37d58130 Mon Sep 17 00:00:00 2001 From: Azul Date: Mon, 14 Jul 2014 21:40:54 +0200 Subject: fix couch tests to use admin credentials --- tests/white-box/couchdb.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'tests') diff --git a/tests/white-box/couchdb.rb b/tests/white-box/couchdb.rb index 74bd47bf..6d3a7452 100644 --- a/tests/white-box/couchdb.rb +++ b/tests/white-box/couchdb.rb @@ -71,7 +71,7 @@ class CouchDB < LeapTest def test_04_Do_ACL_users_exist? acl_users = ['_design/_auth', 'leap_mx', 'nickserver', 'soledad', 'tapicero', 'webapp', 'replication'] - url = couchdb_backend_url("/_users/_all_docs") + url = couchdb_backend_url("/_users/_all_docs", :user => 'admin') assert_get(url) do |body| response = JSON.parse(body) assert_equal acl_users.count, response['total_rows'] @@ -84,7 +84,8 @@ class CouchDB < LeapTest def test_05_Do_required_databases_exist? dbs_that_should_exist = ["customers","identities","keycache","sessions","shared","tickets","tokens","users"] dbs_that_should_exist.each do |db_name| - assert_get(couchdb_url("/"+db_name)) do |body| + url = couchdb_url("/"+db_name, :user => 'admin') + assert_get(url) do |body| assert response = JSON.parse(body) assert_equal db_name, response['db_name'] end @@ -129,9 +130,10 @@ class CouchDB < LeapTest url end - def couchdb_backend_url(path="") + def couchdb_backend_url(path="", options={}) # TODO: admin port is hardcoded for now but should be configurable. - couchdb_url(path, multimaster? && "5986") + options = {port: multimaster? && "5986"}.merge options + couchdb_url(path, options) end def multimaster? -- cgit v1.2.3 From ed292e8ef362e1c5a638480eda02b2ddfde936a7 Mon Sep 17 00:00:00 2001 From: Azul Date: Tue, 15 Jul 2014 13:11:54 +0200 Subject: adopt webapp test to new hiera couch clients format --- tests/white-box/webapp.rb | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'tests') diff --git a/tests/white-box/webapp.rb b/tests/white-box/webapp.rb index 05b86a41..7df57fd7 100644 --- a/tests/white-box/webapp.rb +++ b/tests/white-box/webapp.rb @@ -14,15 +14,16 @@ class Webapp < LeapTest # example properties: # # stunnel: - # couch_client: - # couch1_5984: - # accept_port: 4000 - # connect: couch1.bitmask.i - # connect_port: 15984 + # clients: + # couch_client: + # couch1_5984: + # accept_port: 4000 + # connect: couch1.bitmask.i + # connect_port: 15984 # def test_01_Can_contact_couchdb? - assert_property('stunnel.couch_client') - $node['stunnel']['couch_client'].values.each do |stunnel_conf| + assert_property('stunnel.clients.couch_client') + $node['stunnel']['clients']['couch_client'].values.each do |stunnel_conf| assert port = stunnel_conf['accept_port'], 'Field `accept_port` must be present in `stunnel` property.' local_stunnel_url = "http://localhost:#{port}" remote_ip_address = TCPSocket.gethostbyname(stunnel_conf['connect']).last -- cgit v1.2.3 From 72bad39f8a21c3be33b17134d2e3ca11f5e0d58f Mon Sep 17 00:00:00 2001 From: elijah Date: Tue, 2 Sep 2014 22:02:41 -0700 Subject: tests: make warnings not produce a non-zero exit code, add 'ignore' command to tests, make shorewall optional. --- tests/white-box/network.rb | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'tests') diff --git a/tests/white-box/network.rb b/tests/white-box/network.rb index 118861a7..f2041710 100644 --- a/tests/white-box/network.rb +++ b/tests/white-box/network.rb @@ -26,35 +26,35 @@ class Network < LeapTest # connect: "127.0.0.1:5984" # def test_02_Is_stunnel_running? - if $node['stunnel'] - good_stunnel_pids = [] - $node['stunnel']['clients'].each do |stunnel_type, stunnel_configs| - stunnel_configs.each do |stunnel_name, stunnel_conf| - config_file_name = "/etc/stunnel/#{stunnel_name}.conf" - processes = pgrep(config_file_name) - assert_equal 6, processes.length, "There should be six stunnel processes running for `#{config_file_name}`" - good_stunnel_pids += processes.map{|ps| ps[:pid]} - assert port = stunnel_conf['accept_port'], 'Field `accept_port` must be present in `stunnel` property.' - assert_tcp_socket('localhost', port) - end - end - $node['stunnel']['servers'].each do |stunnel_name, stunnel_conf| + ignore unless $node['stunnel'] + good_stunnel_pids = [] + $node['stunnel']['clients'].each do |stunnel_type, stunnel_configs| + stunnel_configs.each do |stunnel_name, stunnel_conf| config_file_name = "/etc/stunnel/#{stunnel_name}.conf" processes = pgrep(config_file_name) assert_equal 6, processes.length, "There should be six stunnel processes running for `#{config_file_name}`" good_stunnel_pids += processes.map{|ps| ps[:pid]} - assert accept_port = stunnel_conf['accept_port'], "Field `accept` must be present in property `stunnel.servers.#{stunnel_name}`" - assert_tcp_socket('localhost', accept_port) - assert connect_port = stunnel_conf['connect_port'], "Field `connect` must be present in property `stunnel.servers.#{stunnel_name}`" - assert_tcp_socket('localhost', connect_port) + assert port = stunnel_conf['accept_port'], 'Field `accept_port` must be present in `stunnel` property.' + assert_tcp_socket('localhost', port) end - all_stunnel_pids = pgrep('/usr/bin/stunnel').collect{|process| process[:pid]}.uniq - assert_equal good_stunnel_pids.sort, all_stunnel_pids.sort, "There should not be any extra stunnel processes that are not configured in /etc/stunnel" - pass end + $node['stunnel']['servers'].each do |stunnel_name, stunnel_conf| + config_file_name = "/etc/stunnel/#{stunnel_name}.conf" + processes = pgrep(config_file_name) + assert_equal 6, processes.length, "There should be six stunnel processes running for `#{config_file_name}`" + good_stunnel_pids += processes.map{|ps| ps[:pid]} + assert accept_port = stunnel_conf['accept_port'], "Field `accept` must be present in property `stunnel.servers.#{stunnel_name}`" + assert_tcp_socket('localhost', accept_port) + assert connect_port = stunnel_conf['connect_port'], "Field `connect` must be present in property `stunnel.servers.#{stunnel_name}`" + assert_tcp_socket('localhost', connect_port) + end + all_stunnel_pids = pgrep('/usr/bin/stunnel').collect{|process| process[:pid]}.uniq + assert_equal good_stunnel_pids.sort, all_stunnel_pids.sort, "There should not be any extra stunnel processes that are not configured in /etc/stunnel" + pass end def test_03_Is_shorewall_running? + ignore unless File.exists?('/sbin/shorewall') assert_run('/sbin/shorewall status') pass end -- cgit v1.2.3 From a91da714d50b63f4f0b28047000633302cd9a8ea Mon Sep 17 00:00:00 2001 From: Micah Anderson Date: Mon, 15 Sep 2014 16:37:08 -0400 Subject: tests: make shorewall optional Change-Id: I1703ff7b3dafe5d0562a7c34c1851ebfedc569a8 --- tests/white-box/network.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'tests') diff --git a/tests/white-box/network.rb b/tests/white-box/network.rb index 0d98c314..f2041710 100644 --- a/tests/white-box/network.rb +++ b/tests/white-box/network.rb @@ -54,6 +54,7 @@ class Network < LeapTest end def test_03_Is_shorewall_running? + ignore unless File.exists?('/sbin/shorewall') assert_run('/sbin/shorewall status') pass end -- cgit v1.2.3 From 171fc59783a10dc341c435f47313271b89a12c0d Mon Sep 17 00:00:00 2001 From: varac Date: Wed, 17 Sep 2014 11:09:30 +0200 Subject: disable ACL enforcement, because it's a known issue with bigcouch otherwise it will only confuse the user see https://leap.se/code/issues/6030 for more details --- tests/white-box/couchdb.rb | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'tests') diff --git a/tests/white-box/couchdb.rb b/tests/white-box/couchdb.rb index 6d3a7452..a5adb2bf 100644 --- a/tests/white-box/couchdb.rb +++ b/tests/white-box/couchdb.rb @@ -93,20 +93,24 @@ class CouchDB < LeapTest pass end + # disable ACL enforcement, because it's a known issue with bigcouch + # and will only confuse the user + # see https://leap.se/code/issues/6030 for more details # - # for now, this just prints warnings, since we are failing these tests. - # - def test_06_Is_ACL_enforced? - ok = assert_auth_fail( - couchdb_url('/users/_all_docs', :user => 'leap_mx'), - {:limit => 1} - ) - ok = assert_auth_fail( - couchdb_url('/users/_all_docs', :user => 'leap_mx'), - {:limit => 1} - ) && ok - pass if ok - end + ## for now, this just prints warnings, since we are failing these tests. + ## + + #def test_06_Is_ACL_enforced? + # ok = assert_auth_fail( + # couchdb_url('/users/_all_docs', :user => 'leap_mx'), + # {:limit => 1} + # ) + # ok = assert_auth_fail( + # couchdb_url('/users/_all_docs', :user => 'leap_mx'), + # {:limit => 1} + # ) && ok + # pass if ok + #end def test_07_What? pass -- cgit v1.2.3 From 9299574b45de02d417e7237ba49b0222002bbc21 Mon Sep 17 00:00:00 2001 From: elijah Date: Wed, 15 Oct 2014 15:28:54 -0700 Subject: tests - added test that creates user, authenticates, deletes user --- tests/README.md | 27 +++++-- tests/helpers/couchdb_helper.rb | 103 ++++++++++++++++++++++++ tests/helpers/files_helper.rb | 54 +++++++++++++ tests/helpers/http_helper.rb | 145 ++++++++++++++++++++++++++++++++++ tests/helpers/network_helper.rb | 79 +++++++++++++++++++ tests/helpers/os_helper.rb | 34 ++++++++ tests/helpers/srp_helper.rb | 171 ++++++++++++++++++++++++++++++++++++++++ tests/order.rb | 4 + tests/white-box/couchdb.rb | 58 +++++++------- tests/white-box/mx.rb | 50 ++++++++++++ tests/white-box/webapp.rb | 141 +++++++++++++++++++++++---------- 11 files changed, 792 insertions(+), 74 deletions(-) create mode 100644 tests/helpers/couchdb_helper.rb create mode 100644 tests/helpers/files_helper.rb create mode 100644 tests/helpers/http_helper.rb create mode 100644 tests/helpers/network_helper.rb create mode 100644 tests/helpers/os_helper.rb create mode 100644 tests/helpers/srp_helper.rb create mode 100644 tests/white-box/mx.rb (limited to 'tests') diff --git a/tests/README.md b/tests/README.md index debbf700..814c25b1 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,12 +1,25 @@ -This directory contains to kinds of tests: +Tests +--------------------------------- -White Box Tests -================================ +tests/white-box/ -These tests are run on the server as superuser. They are for troubleshooting any problems with the internal setup of the server. + These tests are run on the server as superuser. They are for + troubleshooting any problems with the internal setup of the server. -Black Box Tests -================================ +tests/black-box/ + + These test are run the user's local machine. They are for troubleshooting + any external problems with the service exposed by the server. + +Additional Files +--------------------------------- + +tests/helpers/ + + Utility functions made available to all tests. + +tests/order.rb + + Configuration file to specify which nodes should be tested in which order. -These test are run the user's local machine. They are for troubleshooting any external problems with the service exposed by the server. diff --git a/tests/helpers/couchdb_helper.rb b/tests/helpers/couchdb_helper.rb new file mode 100644 index 00000000..d4d3c0e0 --- /dev/null +++ b/tests/helpers/couchdb_helper.rb @@ -0,0 +1,103 @@ +class LeapTest + + # + # generates a couchdb url for when couchdb is running + # remotely and is available via stunnel. + # + # example properties: + # + # stunnel: + # clients: + # couch_client: + # couch1_5984: + # accept_port: 4000 + # connect: couch1.bitmask.i + # connect_port: 15984 + # + def couchdb_urls_via_stunnel(path="", options=nil) + if options && options[:username] && options[:password] + userpart = "%{username}:%{password}@" % options + else + userpart = "" + end + assert_property('stunnel.clients.couch_client').values.collect do |stunnel_conf| + assert port = stunnel_conf['accept_port'], 'Field `accept_port` must be present in `stunnel` property.' + URLString.new("http://#{userpart}localhost:#{port}#{path}").tap {|url| + remote_ip_address = TCPSocket.gethostbyname(stunnel_conf['connect']).last + url.memo = "(via stunnel to %s:%s, aka %s)" % [stunnel_conf['connect'], stunnel_conf['connect_port'], remote_ip_address] + } + end + end + + # + # generates a couchdb url for accessing couchdb via haproxy + # + # example properties: + # + # haproxy: + # couch: + # listen_port: 4096 + # servers: + # panda: + # backup: false + # host: localhost + # port: 4000 + # weight: 100 + # writable: true + # + def couchdb_url_via_haproxy(path="", options=nil) + if options && options[:username] && options[:password] + userpart = "%{username}:%{password}@" % options + else + userpart = "" + end + port = assert_property('haproxy.couch.listen_port') + return URLString.new("http://#{userpart}localhost:#{port}#{path}").tap { |url| + url.memo = '(via haproxy)' + } + end + + # + # generates a couchdb url for when couchdb is running locally. + # + # example properties: + # + # couch: + # port: 5984 + # + def couchdb_url_via_localhost(path="", options=nil) + port = (options && options[:port]) || assert_property('couch.port') + if options && options[:username] + password = property("couch.users.%{username}.password" % options) + userpart = "%s:%s@" % [options[:username], password] + else + userpart = "" + end + return URLString.new("http://#{userpart}localhost:#{port}#{path}").tap { |url| + url.memo = '(via direct localhost connection)' + } + end + + # + # returns a single url for accessing couchdb + # + def couchdb_url(path="", options=nil) + if property('couch.port') + couchdb_url_via_localhost(path, options) + elsif property('stunnel.clients.couch_client') + couchdb_urls_via_stunnel(path, options).first + end + end + + # + # returns an array of urls for accessing couchdb + # + def couchdb_urls(path="", options=nil) + if property('couch.port') + [couchdb_url_via_localhost(path, options)] + elsif property('stunnel.clients.couch_client') + couchdb_urls_via_stunnel(path, options) + end + end + +end \ No newline at end of file diff --git a/tests/helpers/files_helper.rb b/tests/helpers/files_helper.rb new file mode 100644 index 00000000..d6795889 --- /dev/null +++ b/tests/helpers/files_helper.rb @@ -0,0 +1,54 @@ +class LeapTest + + # + # Matches the regexp in the file, and returns the first matched string (or fails if no match). + # + def file_match(filename, regexp) + if match = File.read(filename).match(regexp) + match.captures.first + else + fail "Regexp #{regexp.inspect} not found in file #{filename.inspect}." + end + end + + # + # Matches the regexp in the file, and returns array of matched strings (or fails if no match). + # + def file_matches(filename, regexp) + if match = File.read(filename).match(regexp) + match.captures + else + fail "Regexp #{regexp.inspect} not found in file #{filename.inspect}." + end + end + + # + # checks to make sure the given property path exists in $node (e.g. hiera.yaml) + # and returns the value + # + def assert_property(property) + latest = $node + property.split('.').each do |segment| + latest = latest[segment] + fail "Required node property `#{property}` is missing." if latest.nil? + end + return latest + end + + # + # a handy function to get the value of a long property path + # without needing to test the existance individually of each part + # in the tree. + # + # e.g. property("stunnel.clients.couch_client") + # + def property(property) + latest = $node + property.split('.').each do |segment| + latest = latest[segment] + return nil if latest.nil? + end + return latest + end + +end \ No newline at end of file diff --git a/tests/helpers/http_helper.rb b/tests/helpers/http_helper.rb new file mode 100644 index 00000000..c941ef63 --- /dev/null +++ b/tests/helpers/http_helper.rb @@ -0,0 +1,145 @@ +require 'net/http' + +class LeapTest + + # + # In order to easily provide detailed error messages, it is useful + # to append a memo to a url string that details what this url is for + # (e.g. stunnel, haproxy, etc). + # + # So, the url happens to be a UrlString, the memo field is used + # if there is an error in assert_get. + # + class URLString < String + attr_accessor :memo + end + + # + # aliases for http_send() + # + def get(url, params=nil, options=nil, &block) + http_send("GET", url, params, options, &block) + end + def delete(url, params=nil, options=nil, &block) + http_send("DELETE", url, params, options, &block) + end + def post(url, params=nil, options=nil, &block) + http_send("POST", url, params, options, &block) + end + def put(url, params=nil, options=nil, &block) + http_send("PUT", url, params, options, &block) + end + + # + # send a GET, DELETE, POST, or PUT + # yields |body, response, error| + # + def http_send(method, url, params=nil, options=nil) + options ||= {} + response = nil + + # build uri + uri = URI(url) + if params && (method == 'GET' || method == 'DELETE') + uri.query = URI.encode_www_form(params) + end + + # build http + http = Net::HTTP.new uri.host, uri.port + if uri.scheme == 'https' + http.verify_mode = OpenSSL::SSL::VERIFY_NONE + http.use_ssl = true + end + + # build request + request = build_request(method, uri, params, options) + + # make http request + http.start do |agent| + response = agent.request(request) + yield response.body, response, nil + end + rescue => exc + yield nil, response, exc + end + + # + # Aliases for assert_http_send() + # + def assert_get(url, params=nil, options=nil, &block) + assert_http_send("GET", url, params, options, &block) + end + def assert_delete(url, params=nil, options=nil, &block) + assert_http_send("DELETE", url, params, options, &block) + end + def assert_post(url, params=nil, options=nil, &block) + assert_http_send("POST", url, params, options, &block) + end + def assert_put(url, params=nil, options=nil, &block) + assert_http_send("PUT", url, params, options, &block) + end + + # + # calls http_send, yielding results if successful or failing with + # descriptive infor otherwise. + # + 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| + if body && response && response.code.to_i >= 200 && response.code.to_i < 300 + if block + yield(body) if block.arity == 1 + 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") + else + fail ["Expected a response from #{url}, but got \"#{error}\" instead.", error_msg, body].compact.join("\n"), error + end + end + end + + # + # only a warning for now, should be a failure in the future + # + def assert_auth_fail(url, params) + uri = URI(url) + get(url, params) do |body, response, error| + unless response.code.to_s == "401" + warn "Expected a '401 Unauthorized' response, but got #{response.code} instead (GET #{uri.request_uri} with username '#{uri.user}')." + return false + end + end + true + end + + private + + def build_request(method, uri, params, options) + request = case method + when "GET" then Net::HTTP::Get.new(uri.request_uri) + when "DELETE" then Net::HTTP::Delete.new(uri.request_uri) + when "POST" then Net::HTTP::Post.new(uri.request_uri) + when "PUT" then Net::HTTP::Put.new(uri.request_uri) + end + if uri.user + request.basic_auth uri.user, uri.password + end + if params && (method == 'POST' || method == 'PUT') + if options[:format] == :json || options[:format] == 'json' + request["Content-Type"] = "application/json" + request.body = params.to_json + else + request.set_form_data(params) if params + end + end + if options[:headers] + options[:headers].each do |key, value| + request[key] = value + end + end + request + end + +end \ No newline at end of file diff --git a/tests/helpers/network_helper.rb b/tests/helpers/network_helper.rb new file mode 100644 index 00000000..ff92d382 --- /dev/null +++ b/tests/helpers/network_helper.rb @@ -0,0 +1,79 @@ +class LeapTest + + # + # tcp connection helper with timeout + # + def try_tcp_connect(host, port, timeout = 5) + addr = Socket.getaddrinfo(host, nil) + sockaddr = Socket.pack_sockaddr_in(port, addr[0][3]) + + Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0).tap do |socket| + socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) + begin + socket.connect_nonblock(sockaddr) + rescue IO::WaitReadable + if IO.select([socket], nil, nil, timeout) == nil + raise "Connection timeout" + else + socket.connect_nonblock(sockaddr) + end + rescue IO::WaitWritable + if IO.select(nil, [socket], nil, timeout) == nil + raise "Connection timeout" + else + socket.connect_nonblock(sockaddr) + end + end + return socket + end + end + + def try_tcp_write(socket, timeout = 5) + begin + socket.write_nonblock("\0") + rescue IO::WaitReadable + if IO.select([socket], nil, nil, timeout) == nil + raise "Write timeout" + else + retry + end + rescue IO::WaitWritable + if IO.select(nil, [socket], nil, timeout) == nil + raise "Write timeout" + else + retry + end + end + end + + def try_tcp_read(socket, timeout = 5) + begin + socket.read_nonblock(1) + rescue IO::WaitReadable + if IO.select([socket], nil, nil, timeout) == nil + raise "Read timeout" + else + retry + end + rescue IO::WaitWritable + if IO.select(nil, [socket], nil, timeout) == nil + raise "Read timeout" + else + retry + end + end + end + + def assert_tcp_socket(host, port, msg=nil) + begin + socket = try_tcp_connect(host, port, 1) + #try_tcp_write(socket,1) + #try_tcp_read(socket,1) + rescue StandardError => exc + fail ["Failed to open socket #{host}:#{port}", exc].join("\n") + ensure + socket.close if socket + end + end + +end \ No newline at end of file diff --git a/tests/helpers/os_helper.rb b/tests/helpers/os_helper.rb new file mode 100644 index 00000000..529e899f --- /dev/null +++ b/tests/helpers/os_helper.rb @@ -0,0 +1,34 @@ +class LeapTest + + # + # works like pgrep command line + # return an array of hashes like so [{:pid => "1234", :process => "ls"}] + # + def pgrep(match) + output = `pgrep --full --list-name '#{match}'` + output.each_line.map{|line| + pid = line.split(' ')[0] + process = line.gsub(/(#{pid} |\n)/, '') + if process =~ /pgrep --full --list-name/ + nil + else + {:pid => pid, :process => process} + end + }.compact + end + + def assert_running(process) + assert pgrep(process).any?, "No running process for #{process}" + end + + # + # runs the specified command, failing on a non-zero exit status. + # + def assert_run(command) + output = `#{command}` + if $?.exitstatus != 0 + fail "Error running `#{command}`:\n#{output}" + end + end + +end \ No newline at end of file diff --git a/tests/helpers/srp_helper.rb b/tests/helpers/srp_helper.rb new file mode 100644 index 00000000..9f4d7f5b --- /dev/null +++ b/tests/helpers/srp_helper.rb @@ -0,0 +1,171 @@ +# +# Here are some very stripped down helper methods for SRP, useful only for +# testing the client side. +# + +require 'digest' +require 'openssl' +require 'securerandom' + +module SRP + + ## + ## UTIL + ## + + module Util + PRIME_N = <<-EOS.split.join.hex +115b8b692e0e045692cf280b436735c77a5a9e8a9e7ed56c965f87db5b2a2ece3 + EOS + BIG_PRIME_N = <<-EOS.split.join.hex # 1024 bits modulus (N) +eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c25657 +6d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089da +d15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e5 +7ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb +06e3 + EOS + GENERATOR = 2 # g + + def hn_xor_hg + byte_xor_hex(sha256_int(BIG_PRIME_N), sha256_int(GENERATOR)) + end + + # a^n (mod m) + def modpow(a, n, m = BIG_PRIME_N) + r = 1 + while true + r = r * a % m if n[0] == 1 + n >>= 1 + return r if n == 0 + a = a * a % m + end + end + + # Hashes the (long) int args + def sha256_int(*args) + sha256_hex(*args.map{|a| "%02x" % a}) + end + + # Hashes the hex args + def sha256_hex(*args) + h = args.map{|a| a.length.odd? ? "0#{a}" : a }.join('') + sha256_str([h].pack('H*')) + end + + def sha256_str(s) + Digest::SHA2.hexdigest(s) + end + + def bigrand(bytes) + OpenSSL::Random.random_bytes(bytes).unpack("H*")[0] + end + + def multiplier + @muliplier ||= calculate_multiplier + end + + protected + + def calculate_multiplier + sha256_int(BIG_PRIME_N, GENERATOR).hex + end + + def byte_xor_hex(a, b) + a = [a].pack('H*') + b = [b].pack('H*') + a.bytes.each_with_index.map do |a_byte, i| + (a_byte ^ (b[i].ord || 0)).chr + end.join + end + end + + ## + ## SESSION + ## + + class Session + include SRP::Util + attr_accessor :user + attr_accessor :bb + + def initialize(user, aa=nil) + @user = user + @a = bigrand(32).hex + end + + def m + @m ||= sha256_hex(n_xor_g_long, login_hash, @user.salt.to_s(16), aa, bb, k) + end + + def aa + @aa ||= modpow(GENERATOR, @a).to_s(16) # A = g^a (mod N) + end + + protected + + # client: K = H( (B - kg^x) ^ (a + ux) ) + def client_secret + base = bb.hex + base -= modpow(GENERATOR, @user.private_key) * multiplier + base = base % BIG_PRIME_N + modpow(base, @user.private_key * u.hex + @a) + end + + def k + @k ||= sha256_int(client_secret) + end + + def n_xor_g_long + @n_xor_g_long ||= hn_xor_hg.bytes.map{|b| "%02x" % b.ord}.join + end + + def login_hash + @login_hash ||= sha256_str(@user.username) + end + + def u + @u ||= sha256_hex(aa, bb) + end + end + + ## + ## Dummy USER + ## + + class User + include SRP::Util + + attr_accessor :username + attr_accessor :password + attr_accessor :salt + attr_accessor :verifier + + 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) + end + + def private_key + @private_key ||= calculate_private_key + end + + def to_params + { + 'user[login]' => @username, + 'user[password_verifier]' => @verifier.to_s(16), + 'user[password_salt]' => @salt.to_s(16) + } + end + + private + + def calculate_private_key + shex = '%x' % [@salt] + inner = sha256_str([@username, @password].join(':')) + sha256_hex(shex, inner).hex + end + end + +end diff --git a/tests/order.rb b/tests/order.rb index ffa6ae4e..4468686f 100644 --- a/tests/order.rb +++ b/tests/order.rb @@ -3,6 +3,10 @@ class LeapCli::Config::Node # returns a list of node names that should be tested before this node. # make sure to not return ourselves (please no dependency loops!). # + # NOTE: this method determines the order that nodes are tested in. To specify + # the order of tests on a particular node, each test can call class method + # LeapTest.depends_on(). + # def test_dependencies dependents = LeapCli::Config::ObjectList.new unless services.include?('couchdb') diff --git a/tests/white-box/couchdb.rb b/tests/white-box/couchdb.rb index a5adb2bf..d438b193 100644 --- a/tests/white-box/couchdb.rb +++ b/tests/white-box/couchdb.rb @@ -52,7 +52,7 @@ class CouchDB < LeapTest # def test_03_Are_configured_nodes_online? return unless multimaster? - url = couchdb_url("/_membership", :user => 'admin') + url = couchdb_url("/_membership", :username => 'admin') assert_get(url) do |body| response = JSON.parse(body) nodes_configured_but_not_available = response['cluster_nodes'] - response['all_nodes'] @@ -71,7 +71,7 @@ class CouchDB < LeapTest def test_04_Do_ACL_users_exist? acl_users = ['_design/_auth', 'leap_mx', 'nickserver', 'soledad', 'tapicero', 'webapp', 'replication'] - url = couchdb_backend_url("/_users/_all_docs", :user => 'admin') + url = couchdb_backend_url("/_users/_all_docs", :username => 'admin') assert_get(url) do |body| response = JSON.parse(body) assert_equal acl_users.count, response['total_rows'] @@ -84,7 +84,7 @@ class CouchDB < LeapTest def test_05_Do_required_databases_exist? dbs_that_should_exist = ["customers","identities","keycache","sessions","shared","tickets","tokens","users"] dbs_that_should_exist.each do |db_name| - url = couchdb_url("/"+db_name, :user => 'admin') + url = couchdb_url("/"+db_name, :username => 'admin') assert_get(url) do |body| assert response = JSON.parse(body) assert_equal db_name, response['db_name'] @@ -102,50 +102,54 @@ class CouchDB < LeapTest #def test_06_Is_ACL_enforced? # ok = assert_auth_fail( - # couchdb_url('/users/_all_docs', :user => 'leap_mx'), + # couchdb_url('/users/_all_docs', :username => 'leap_mx'), # {:limit => 1} # ) # ok = assert_auth_fail( - # couchdb_url('/users/_all_docs', :user => 'leap_mx'), + # couchdb_url('/users/_all_docs', :username => 'leap_mx'), # {:limit => 1} # ) && ok # pass if ok #end - def test_07_What? + def test_07_Can_records_be_created? + token = Token.new + url = couchdb_url("/tokens", :username => 'admin') + assert_post(url, token, :format => :json) do |body| + assert response = JSON.parse(body), "POST response should be JSON" + assert response["ok"], "POST response should be OK" + assert_delete(File.join(url, response["id"]), :rev => response["rev"]) do |body| + assert response = JSON.parse(body), "DELETE response should be JSON" + assert response["ok"], "DELETE response should be OK" + end + end pass end private - def couchdb_url(path="", options=nil) - options||={} - @port ||= begin - assert_property 'couch.port' - $node['couch']['port'] - end - url = 'http://' - if options[:user] - assert_property 'couch.users.' + options[:user] - password = $node['couch']['users'][options[:user]]['password'] - url += "%s:%s@" % [options[:user], password] - end - url += "localhost:#{options[:port] || @port}#{path}" - url + def multimaster? + mode == "multimaster" end + def mode + assert_property('couch.mode') + end + + # TODO: admin port is hardcoded for now but should be configurable. def couchdb_backend_url(path="", options={}) - # TODO: admin port is hardcoded for now but should be configurable. options = {port: multimaster? && "5986"}.merge options couchdb_url(path, options) end - def multimaster? - mode == "multimaster" - end - - def mode - assert_property('couch.mode') + require 'securerandom' + require 'digest/sha2' + class Token < Hash + def initialize + self['token'] = SecureRandom.urlsafe_base64(32).gsub(/^_*/, '') + self['_id'] = Digest::SHA512.hexdigest(self['token']) + self['last_seen_at'] = Time.now + end end end diff --git a/tests/white-box/mx.rb b/tests/white-box/mx.rb new file mode 100644 index 00000000..da780de4 --- /dev/null +++ b/tests/white-box/mx.rb @@ -0,0 +1,50 @@ +raise SkipTest unless $node["services"].include?("mx") + +require 'json' + +class Mx < LeapTest + depends_on "Network" + + def setup + end + + def test_01_Can_contact_couchdb? + dbs = ["identities"] + dbs.each do |db_name| + couchdb_urls("/"+db_name, url_options).each do |url| + assert_get(url) do |body| + assert response = JSON.parse(body) + assert_equal db_name, response['db_name'] + end + end + end + pass + end + + def test_02_Can_contact_couchdb_via_haproxy? + if property('haproxy.couch') + url = couchdb_url_via_haproxy("", url_options) + assert_get(url) do |body| + assert_match /"couchdb":"Welcome"/, body, "Request to #{url} should return couchdb welcome message." + end + pass + end + end + + def test_03_Are_MX_daemons_running? + assert_running 'leap_mx' + assert_running '/usr/lib/postfix/master' + assert_running '/usr/sbin/unbound' + pass + end + + private + + def url_options + { + :username => property('couchdb_leap_mx_user.username'), + :password => property('couchdb_leap_mx_user.password') + } + end + +end diff --git a/tests/white-box/webapp.rb b/tests/white-box/webapp.rb index 7df57fd7..0fea1c7f 100644 --- a/tests/white-box/webapp.rb +++ b/tests/white-box/webapp.rb @@ -1,58 +1,29 @@ raise SkipTest unless $node["services"].include?("webapp") -require 'socket' +require 'json' class Webapp < LeapTest depends_on "Network" - HAPROXY_CONFIG = '/etc/haproxy/haproxy.cfg' - def setup end - # - # example properties: - # - # stunnel: - # clients: - # couch_client: - # couch1_5984: - # accept_port: 4000 - # connect: couch1.bitmask.i - # connect_port: 15984 - # def test_01_Can_contact_couchdb? - assert_property('stunnel.clients.couch_client') - $node['stunnel']['clients']['couch_client'].values.each do |stunnel_conf| - assert port = stunnel_conf['accept_port'], 'Field `accept_port` must be present in `stunnel` property.' - local_stunnel_url = "http://localhost:#{port}" - remote_ip_address = TCPSocket.gethostbyname(stunnel_conf['connect']).last - msg = "(stunnel to %s:%s, aka %s)" % [stunnel_conf['connect'], stunnel_conf['connect_port'], remote_ip_address] - assert_get(local_stunnel_url, nil, error_msg: msg) do |body| - assert_match /"couchdb":"Welcome"/, body, "Request to #{local_stunnel_url} should return couchdb welcome message." - end + url = couchdb_url("", url_options) + assert_get(url) do |body| + assert_match /"couchdb":"Welcome"/, body, "Request to #{url} should return couchdb welcome message." end pass end - # - # example properties: - # - # haproxy: - # servers: - # couch1: - # backup: false - # host: localhost - # port: 4000 - # weight: 10 - # - def test_02_Is_haproxy_working? - port = file_match(HAPROXY_CONFIG, /^ bind localhost:(\d+)$/) - url = "http://localhost:#{port}" - assert_get(url) do |body| - assert_match /"couchdb":"Welcome"/, body, "Request to #{url} should return couchdb welcome message." + def test_02_Can_contact_couchdb_via_haproxy? + if property('haproxy.couch') + url = couchdb_url_via_haproxy("", url_options) + assert_get(url) do |body| + assert_match /"couchdb":"Welcome"/, body, "Request to #{url} should return couchdb welcome message." + end + pass end - pass end def test_03_Are_daemons_running? @@ -70,4 +41,94 @@ 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 + 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') + pass + end + end + end + end + + private + + def url_options + { + :username => property('couchdb_webapp_user.username'), + :password => property('couchdb_webapp_user.password') + } + end + + def api_url(path) + "https://%{domain}:%{port}#{path}" % { + :domain => property('api.domain'), + :port => property('api.port') + } + 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 From 6200be6fbf1f05665158e9ce8b218433f2440240 Mon Sep 17 00:00:00 2001 From: elijah Date: Wed, 19 Nov 2014 11:37:45 -0800 Subject: test if soledad daemon is running --- tests/white-box/couchdb.rb | 2 +- tests/white-box/mx.rb | 2 +- tests/white-box/openvpn.rb | 4 ++-- tests/white-box/soledad.rb | 17 +++++++++++++++++ tests/white-box/webapp.rb | 2 +- 5 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 tests/white-box/soledad.rb (limited to 'tests') diff --git a/tests/white-box/couchdb.rb b/tests/white-box/couchdb.rb index d438b193..2788f4f7 100644 --- a/tests/white-box/couchdb.rb +++ b/tests/white-box/couchdb.rb @@ -1,4 +1,4 @@ -raise SkipTest unless $node["services"].include?("couchdb") +raise SkipTest unless service?(:couchdb) require 'json' diff --git a/tests/white-box/mx.rb b/tests/white-box/mx.rb index da780de4..794a9a41 100644 --- a/tests/white-box/mx.rb +++ b/tests/white-box/mx.rb @@ -1,4 +1,4 @@ -raise SkipTest unless $node["services"].include?("mx") +raise SkipTest unless service?(:mx) require 'json' diff --git a/tests/white-box/openvpn.rb b/tests/white-box/openvpn.rb index 5eb2bdb5..23a40426 100644 --- a/tests/white-box/openvpn.rb +++ b/tests/white-box/openvpn.rb @@ -1,6 +1,6 @@ -raise SkipTest unless $node["services"].include?("openvpn") +raise SkipTest unless service?(:openvpn) -class Openvpn < LeapTest +class OpenVPN < LeapTest depends_on "Network" def setup diff --git a/tests/white-box/soledad.rb b/tests/white-box/soledad.rb new file mode 100644 index 00000000..5a13e4a6 --- /dev/null +++ b/tests/white-box/soledad.rb @@ -0,0 +1,17 @@ +raise SkipTest unless service?(:soledad) + +require 'json' + +class Soledad < LeapTest + depends_on "Network" + depends_on "CouchDB" if service?(:couchdb) + + def setup + end + + def test_00_Is_Soledad_running? + assert_running 'soledad' + pass + end + +end diff --git a/tests/white-box/webapp.rb b/tests/white-box/webapp.rb index 0fea1c7f..2aa87403 100644 --- a/tests/white-box/webapp.rb +++ b/tests/white-box/webapp.rb @@ -1,4 +1,4 @@ -raise SkipTest unless $node["services"].include?("webapp") +raise SkipTest unless service?(:webapp) require 'json' -- cgit v1.2.3 From e7c1e86a4a63def83ff205319e0950e4d3421180 Mon Sep 17 00:00:00 2001 From: elijah Date: Tue, 25 Nov 2014 16:52:24 -0800 Subject: atomic tests for webapp api --- tests/white-box/webapp.rb | 82 ++++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 47 deletions(-) (limited to 'tests') diff --git a/tests/white-box/webapp.rb b/tests/white-box/webapp.rb index 2aa87403..7fbab1af 100644 --- a/tests/white-box/webapp.rb +++ b/tests/white-box/webapp.rb @@ -41,62 +41,50 @@ class Webapp < LeapTest pass end - def test_05_Can_create_user? - @@user = nil - user = SRP::User.new + def test_05_Can_create_and_authenticate_and_delete_user_via_API? + @user = SRP::User.new + @session_token = nil + @user_id = nil + + # create user url = api_url("/1/users.json") - assert_post(url, user.to_params) do |body| + 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 - 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 + # authenticate + 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(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 + 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 - 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') - pass - end + # delete + 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') + pass end end end -- cgit v1.2.3 From 69067b64942fad72bd0ec9eeab7f161ef4a16ee3 Mon Sep 17 00:00:00 2001 From: elijah Date: Sun, 30 Nov 2014 22:19:20 -0800 Subject: minor: ensure there is only one tapicero process --- tests/helpers/os_helper.rb | 8 ++++++-- tests/white-box/couchdb.rb | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'tests') 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/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' -- cgit v1.2.3 From acd6dd2848f38ba1b728f263f297bc6d2ad9e4bb Mon Sep 17 00:00:00 2001 From: elijah Date: Tue, 2 Dec 2014 23:47:35 -0800 Subject: add soledad sync test to `leap test`. closes #6431 --- tests/helpers/bonafide_helper.rb | 87 ++++++++++++++++++++++++++++++++++++++++ tests/helpers/soledad_sync.py | 76 +++++++++++++++++++++++++++++++++++ tests/helpers/srp_helper.rb | 6 +-- tests/white-box/webapp.rb | 87 +++++++++++++++++++--------------------- 4 files changed, 206 insertions(+), 50 deletions(-) create mode 100644 tests/helpers/bonafide_helper.rb create mode 100755 tests/helpers/soledad_sync.py (limited to 'tests') diff --git a/tests/helpers/bonafide_helper.rb b/tests/helpers/bonafide_helper.rb new file mode 100644 index 00000000..c84ea142 --- /dev/null +++ b/tests/helpers/bonafide_helper.rb @@ -0,0 +1,87 @@ +# +# 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? + rescue + # ^^ ensure here would eat any failed assertions + assert_delete_user(user) + raise + 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' + 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 + url = api_url("/1/users/#{user.id}.json") + options = {:headers => { + "Authorization" => "Token token=\"#{user.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') + pass + end + end + end + end + +end diff --git a/tests/helpers/soledad_sync.py b/tests/helpers/soledad_sync.py new file mode 100755 index 00000000..54b6f34b --- /dev/null +++ b/tests/helpers/soledad_sync.py @@ -0,0 +1,76 @@ +#!/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 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)) + exit(2) diff --git a/tests/helpers/srp_helper.rb b/tests/helpers/srp_helper.rb index 9f4d7f5b..0aa1b1fb 100644 --- a/tests/helpers/srp_helper.rb +++ b/tests/helpers/srp_helper.rb @@ -135,16 +135,14 @@ 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 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 end def private_key diff --git a/tests/white-box/webapp.rb b/tests/white-box/webapp.rb index 7fbab1af..d2419ab4 100644 --- a/tests/white-box/webapp.rb +++ b/tests/white-box/webapp.rb @@ -42,50 +42,23 @@ class Webapp < LeapTest end def test_05_Can_create_and_authenticate_and_delete_user_via_API? - @user = SRP::User.new - @session_token = nil - @user_id = nil - - # create user - 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 - - # authenticate - 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 + assert_tmp_user + pass + end - # delete - 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) + assert_tmp_user do |user| + assert user_db_exists?(user), "Could not find user db for test user #{user.username}" + 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 + else + skip 'No soledad service configuration' end end @@ -98,11 +71,33 @@ 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 + hostname = soledad_config['hosts'][host_name]['hostname'] + port = soledad_config['hosts'][host_name]['port'] + return "#{hostname}:#{port}" + end + + # + # returns true if the per-user db created by tapicero exists. + # we try three times, and give up after that. + # + def user_db_exists?(user) + 3.times do + sleep 0.1 + get(couchdb_url("/user-#{user.id}/_design/docs")) do |body, response, error| + if response.code.to_i == 200 + return true + end + end + sleep 0.2 + end + return false end # -- cgit v1.2.3 From 7ca1a6feb2f881f2a99b624c266f0779d2402ff9 Mon Sep 17 00:00:00 2001 From: elijah Date: Thu, 4 Dec 2014 15:16:25 -0800 Subject: tests - better errors, ensure tmp users are deleted, remove bad 'pass()' call that made tmp_user tests always succeed. --- tests/helpers/bonafide_helper.rb | 22 +++++++++++----------- tests/helpers/soledad_sync.py | 2 ++ tests/helpers/srp_helper.rb | 4 +++- tests/white-box/webapp.rb | 10 ++++++---- 4 files changed, 22 insertions(+), 16 deletions(-) (limited to 'tests') diff --git a/tests/helpers/bonafide_helper.rb b/tests/helpers/bonafide_helper.rb index c84ea142..d96b3977 100644 --- a/tests/helpers/bonafide_helper.rb +++ b/tests/helpers/bonafide_helper.rb @@ -8,10 +8,13 @@ class LeapTest user = assert_create_user assert_authenticate_user(user) yield user if block_given? - rescue - # ^^ ensure here would eat any failed assertions assert_delete_user(user) - raise + rescue StandardError, MiniTest::Assertion => exc + begin + assert_delete_user(user) + rescue + end + raise exc end def api_url(path) @@ -67,19 +70,16 @@ 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 + 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}\"" }} + user.deleted = true 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') - pass - end + 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 end diff --git a/tests/helpers/soledad_sync.py b/tests/helpers/soledad_sync.py index 54b6f34b..2fb865fc 100755 --- a/tests/helpers/soledad_sync.py +++ b/tests/helpers/soledad_sync.py @@ -19,6 +19,7 @@ import os import sys +import traceback import tempfile import shutil import u1db @@ -73,4 +74,5 @@ if __name__ == '__main__': 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 0aa1b1fb..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,7 +136,7 @@ d15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e5 class User include SRP::Util - attr_accessor :username, :password, :salt, :verifier, :id, :session_token, :ok + attr_accessor :username, :password, :salt, :verifier, :id, :session_token, :ok, :deleted def initialize @username = "test_user_" + SecureRandom.urlsafe_base64(10).downcase.gsub(/[_-]/, '') @@ -143,6 +144,7 @@ d15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e5 @salt = bigrand(4).hex @verifier = modpow(GENERATOR, private_key) @ok = false + @deleted = false end def private_key diff --git a/tests/white-box/webapp.rb b/tests/white-box/webapp.rb index d2419ab4..d5d41833 100644 --- a/tests/white-box/webapp.rb +++ b/tests/white-box/webapp.rb @@ -51,7 +51,7 @@ class Webapp < LeapTest if soledad_config && !soledad_config.empty? soledad_server = pick_soledad_server(soledad_config) assert_tmp_user do |user| - assert user_db_exists?(user), "Could not find user db for test user #{user.username}" + 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}" @@ -87,17 +87,19 @@ class Webapp < LeapTest # returns true if the per-user db created by tapicero exists. # we try three times, and give up after that. # - def user_db_exists?(user) + 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 true + return end end sleep 0.2 end - return false + assert false, "Could not find user db for test user #{user.username}\nuuid=#{user.id}\nHTTP #{last_response.code} #{last_error} #{last_body}" end # -- cgit v1.2.3 From 723caa71b527132bc58ed5daeacbabdbf59b7199 Mon Sep 17 00:00:00 2001 From: elijah Date: Tue, 9 Dec 2014 11:11:50 -0800 Subject: added http verb to test error messages --- tests/helpers/http_helper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests') 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 -- cgit v1.2.3 From aedd6a57b5bf2a5d53cb19d181f90d78918ddf75 Mon Sep 17 00:00:00 2001 From: elijah Date: Mon, 15 Dec 2014 16:06:27 -0800 Subject: bugfix: identities of test users must be also destroyed. closes #6550. --- tests/helpers/bonafide_helper.rb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/helpers/bonafide_helper.rb b/tests/helpers/bonafide_helper.rb index d96b3977..faf8c1f4 100644 --- a/tests/helpers/bonafide_helper.rb +++ b/tests/helpers/bonafide_helper.rb @@ -75,12 +75,24 @@ class LeapTest options = {:headers => { "Authorization" => "Token token=\"#{user.session_token}\"" }} + params = { + :identities => 'destroy' + } user.deleted = true - delete(url, {}, options) do |body, response, error| + 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 -- cgit v1.2.3 From b49fc6c4a864c6e42a4fd4deae25c0ab2eb564ea Mon Sep 17 00:00:00 2001 From: elijah Date: Wed, 17 Dec 2014 16:22:29 -0800 Subject: tests: don't run soledad test if there are no soledad nodes --- tests/helpers/bonafide_helper.rb | 2 +- tests/white-box/webapp.rb | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) (limited to 'tests') diff --git a/tests/helpers/bonafide_helper.rb b/tests/helpers/bonafide_helper.rb index faf8c1f4..9b26eaaf 100644 --- a/tests/helpers/bonafide_helper.rb +++ b/tests/helpers/bonafide_helper.rb @@ -34,7 +34,7 @@ class LeapTest 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' + assert response['ok'], "Creating a user should be successful, got #{response.inspect} instead." end user.ok = true return user diff --git a/tests/white-box/webapp.rb b/tests/white-box/webapp.rb index d5d41833..9f104899 100644 --- a/tests/white-box/webapp.rb +++ b/tests/white-box/webapp.rb @@ -50,12 +50,14 @@ class Webapp < LeapTest soledad_config = property('definition_files.soledad_service') if soledad_config && !soledad_config.empty? soledad_server = pick_soledad_server(soledad_config) - 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 + 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' @@ -78,9 +80,13 @@ class Webapp < LeapTest def pick_soledad_server(soledad_config_json_str) soledad_config = JSON.parse(soledad_config_json_str) host_name = soledad_config['hosts'].keys.shuffle.first - hostname = soledad_config['hosts'][host_name]['hostname'] - port = soledad_config['hosts'][host_name]['port'] - return "#{hostname}:#{port}" + 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 # -- cgit v1.2.3