diff --git a/features/patroni_api.feature b/features/patroni_api.feature index 78f014e2..6eedc26c 100644 --- a/features/patroni_api.feature +++ b/features/patroni_api.feature @@ -14,10 +14,10 @@ Scenario: check API requests on a stand-alone server Then I receive a response code 503 And I receive a response text "I am the leader, can not reinitialize" When I issue a POST request to http://127.0.0.1:8008/failover with leader=postgres0 - Then I receive a response code 503 + Then I receive a response code 500 And I receive a response text "failover is not possible: cluster does not have members except leader" When I issue an empty POST request to http://127.0.0.1:8008/failover - Then I receive a response code 503 + Then I receive a response code 500 And I receive a response text "No values given for required parameters leader and member" Scenario: check API requests for the primary-replica pair @@ -34,8 +34,15 @@ Scenario: check API requests for the primary-replica pair Then I receive a response code 200 And postgres0 is a leader after 5 seconds -Scenario: check promotion via the API +Scenario: check the failover via the API Given I issue a POST request to http://127.0.0.1:8008/failover with leader=postgres0,candidate=postgres1 Then I receive a response code 200 And postgres1 is a leader after 5 seconds And replication works from postgres1 to postgres0 after 15 seconds + +Scenario: check the scheduled failover + Given I issue a scheduled failover at http://127.0.0.1:8009 from postgres1 to postgresq0 in 10 seconds + Then I receive a response code 200 + And postgres0 is a leader after 15 seconds + And replication works from postgres0 to postgres1 after 25 seconds + diff --git a/features/patroni_api.py b/features/patroni_api.py index 37650d99..0659bc2c 100644 --- a/features/patroni_api.py +++ b/features/patroni_api.py @@ -1,5 +1,7 @@ +from datetime import datetime, timedelta from lettuce import world, steps import time +import pytz import requests @@ -49,7 +51,7 @@ class PatroniAPISteps(object): self.do_post(step, url, None) def do_post(self, step, url, data): - '''I issue a POST request to (https?://(?:\w|\.|:|/)+) with ((?:\s*\w+\s*=\s*\w+\s*,?)+)''' + '''I issue a POST request to (https?://(?:\w|\.|:|/)+) with ((?:\w+=(?:\w|\.|:|-|\+|\s)+,?)+)''' post_data = {} if data: post_components = data.split(',') @@ -72,7 +74,8 @@ class PatroniAPISteps(object): def check_response(self, step, component, data): '''I receive a response (\w+) (.*)''' if component == 'code': - assert self.status_code == int(data), "status code {0} != {1}".format(self.status_code, int(data)) + assert self.status_code == int(data),\ + "status code {0} != {1}, response: {2}".format(self.status_code, int(data), self.response) elif component == 'text': assert self.response == data.strip('"'), "response {0} does not contain {1}".format(self.response, data) else: @@ -86,5 +89,11 @@ class PatroniAPISteps(object): Then table test_{0} is present on {2} after {3} seconds """.format(int(time.time()), master, replica, time_limit)) + def scheduld_failover(self, step, at_url, from_host, to_host, in_seconds): + '''I issue a scheduled failover at (https?://(?:\w|\.|:|/)+) from (\w+) to (\w+) in (\d+) seconds''' + step.behave_as(""" + Given I issue a POST request to {0}/failover with leader={1},candidate={2},scheduled_at={3} + """.format(at_url, from_host, to_host, datetime.now(pytz.utc) + timedelta(seconds=int(in_seconds)))) + PatroniAPISteps(world)