def test_execute_request_params(): session = Session(load_questions=False) # Unmodified work item work_item = WorkItem(session) witem = __execute_and_return_request_params(work_item, session) assert "TESTARG" not in witem session.additional_args["TESTARG"] = "addl" # Work item with additional args work_item = WorkItem(session) witem = __execute_and_return_request_params(work_item, session) assert witem.get("TESTARG") == "addl" # Work item with additional args and extra args work_item = WorkItem(session) witem = __execute_and_return_request_params( work_item, session, extra_args={"TESTARG": "extra"}) assert witem.get("TESTARG") == "extra" # Confirm additional args not messed up work_item = WorkItem(session) witem = __execute_and_return_request_params(work_item, session) assert witem.get("TESTARG") == "addl"
def test_print_workstatus_old_task_subtasks(caplog): session = Session(load_questions=False) session.stale_timeout = 5 nowFunction = lambda tzinfo: datetime.datetime( 2017, 12, 20, 0, 0, 0, 0, tzinfo=tzinfo ) workStatus = "TEST" taskDetails = json.dumps( { "obtained": "2016-11-22 10:43:21 UTC", "batches": [ { "completed": 1, "description": "Fooing the bar", "size": 2, "startDate": "2016-11-22 10:43:22 UTC", } ], } ) _print_work_status_helper(session, workStatus, taskDetails, nowFunction) assert "status: TEST" in caplog.text assert ( ".... {obtained} Fooing the bar 1 / 2. (1y27d13:16:39 elapsed)".format( obtained=_print_timestamp( _parse_timestamp(json.loads(taskDetails)["obtained"]) ) ) in caplog.text )
def test_execute_request_params(): session = Session(load_questions=False) # Unmodified work item work_item = WorkItem(session) witem = __execute_and_return_request_params(work_item, session) assert 'TESTARG' not in witem session.additional_args['TESTARG'] = 'addl' # Work item with additional args work_item = WorkItem(session) witem = __execute_and_return_request_params(work_item, session) assert witem.get('TESTARG') == 'addl' # Work item with additional args and extra args work_item = WorkItem(session) witem = __execute_and_return_request_params( work_item, session, extra_args={'TESTARG': 'extra'}) assert witem.get('TESTARG') == 'extra' # Confirm additional args not messed up work_item = WorkItem(session) witem = __execute_and_return_request_params(work_item, session) assert witem.get('TESTARG') == 'addl'
def test_print_workstatus_fresh_task(caplog): session = Session(load_questions=False) session.stale_timeout = 5 nowFunction = lambda tzinfo: datetime.datetime( 2017, 12, 20, 0, 0, 0, 0, tzinfo=tzinfo ) workStatus = "TEST" taskDetails = json.dumps( { "obtained": "2017-12-20 00:00:00 UTC", "batches": [ { "completed": 0, "description": "Fooing the bar", "size": 0, "startDate": "2017-12-20 00:00:00 UTC", } ], } ) _print_work_status_helper(session, workStatus, taskDetails, nowFunction) assert "status: TEST" in caplog.text assert ( ".... {obtained} Fooing the bar".format( obtained=_print_timestamp( _parse_timestamp(json.loads(taskDetails)["obtained"]) ) ) in caplog.text )
def test_get_session_bad(): """Confirm an exception is thrown when a bad session type passed in.""" bogus_type = "bogus_session_type" with pytest.raises(ValueError) as e: Session.get(type_=bogus_type) e_msg = str(e.value) assert "Invalid session type" in e_msg assert "type '{}' does not match".format(bogus_type) in e_msg
def __init__(self, snapshot_dir, host="localhost"): if not os.path.exists(snapshot_dir): raise ValueError( "Snapshot directory '{}' does not exist".format(snapshot_dir)) self._bf = Session(host=host) self._bf.set_network("manrs-test") self._bf.init_snapshot(snapshot_dir, name="manrs-test", overwrite=True) self.node_properties = self._bf.q.nodeProperties().answer() self.interface_properties = self._bf.q.interfaceProperties().answer() self.bgp_peer_properties = self._bf.q.bgpPeerConfiguration().answer()
def init_snapshots(question_categories: Mapping, session: Session) -> None: """Initialize all snapshots needed for generating question notebooks.""" snapshot_set: Set[Tuple[str, str]] = collect_snapshots(question_categories) logging.info("Initializing snapshots") for snapshot_config in progressbar.progressbar(snapshot_set): snapshot_path = _DOC_DIR / snapshot_config.path session.init_snapshot(str(snapshot_path), name=snapshot_config.name, overwrite=True)
def bf(network_name, snapshot_name): """Batfish session fixture""" try: bf = Session.get('bfe') os.environ["SESSION_TYPE"] = 'bfe' except: bf = Session.get('bf') os.environ["SESSION_TYPE"] = 'bf' bf.enable_diagnostics = False bf.set_network(network_name) bf.set_snapshot(snapshot_name) return bf
def test_get_facts_questions(): """Test that get facts calls the right questions, passing through the right args.""" bf = Session(load_questions=False) nodes = 'foo' with patch.object(bf.q, 'nodeProperties', create=True) as mock_node, \ patch.object(bf.q, 'interfaceProperties', create=True) as mock_iface, \ patch.object(bf.q, 'bgpPeerConfiguration', create=True) as mock_peers, \ patch.object(bf.q, 'bgpProcessConfiguration', create=True) as mock_proc: mock_node.return_value = MockQuestion(MockTableAnswer()) mock_iface.return_value = MockQuestion(MockTableAnswer()) mock_proc.return_value = MockQuestion(MockTableAnswer()) mock_peers.return_value = MockQuestion(MockTableAnswer()) get_facts(bf, nodes) mock_node.assert_called_with(nodes=nodes) mock_iface.assert_called_with(nodes=nodes) mock_proc.assert_called_with(nodes=nodes) mock_peers.assert_called_with(nodes=nodes)
def init_batfish(self): """Initialize Batfish snapshot and session.""" network_name = config.SETTINGS.batfish.network_name snapshot_name = config.SETTINGS.batfish.snapshot_name snapshot_path = config.SETTINGS.main.configs_directory bf_params = dict( host=config.SETTINGS.batfish.address, port_v1=config.SETTINGS.batfish.port_v1, port_v2=config.SETTINGS.batfish.port_v2, ssl=config.SETTINGS.batfish.use_ssl, ) if config.SETTINGS.batfish.api_key: bf_params["api_key"] = config.SETTINGS.batfish.api_key try: self.bfi = Session.get("bf", **bf_params) self.bfi.verify = False self.bfi.set_network(network_name) self.bfi.init_snapshot(snapshot_path, name=snapshot_name, overwrite=True) except BatfishException as exc: error = json.loads(str(exc).splitlines()[-1]) error = re.sub(r"[^:]*:.", "", error["answerElements"][0]["answer"][0]) raise AdapterLoadFatalError(error) from exc
def test_filter_permits_from_session(): """Confirm filter-permits assert passes and fails as expected when called from a session.""" headers = HeaderConstraints(srcIps="1.1.1.1") bf = Session(load_questions=False) with patch.object(bf.q, "searchFilters", create=True) as mock_search_filters: # Test success mock_search_filters.return_value = MockQuestion() bf.asserts.assert_filter_permits("filter", headers) mock_search_filters.assert_called_with(filters="filter", headers=headers, action="deny") # Test failure; also test that startLocation is passed through mock_df = DataFrame.from_records([{"Flow": "found", "More": "data"}]) mock_search_filters.return_value = MockQuestion( MockTableAnswer(mock_df)) with pytest.raises(BatfishAssertException) as excinfo: bf.asserts.assert_filter_permits("filter", headers, startLocation="Ethernet1") # Ensure found answer is printed assert mock_df.to_string() in str(excinfo.value) mock_search_filters.assert_called_with(filters="filter", headers=headers, startLocation="Ethernet1", action="deny")
def test_no_incompatible_ospf_sessions(): """Confirm no-incompatible-ospf-sessions assert passes and fails as expected when specifying a session.""" bf = Session(load_questions=False) with patch.object(bf.q, 'ospfSessionCompatibility', create=True) as ospfSessionCompatibility: # Test success ospfSessionCompatibility.return_value = MockQuestion() assert_no_incompatible_ospf_sessions(nodes='nodes', remote_nodes='remote_nodes', session=bf) ospfSessionCompatibility.assert_called_with(nodes='nodes', remote_nodes='remote_nodes', statuses=UNESTABLISHED_OSPF_SESSION_STATUS_SPEC) # Test failure mock_df = DataFrame.from_records([{'Session': 'found', 'More': 'data'}]) ospfSessionCompatibility.return_value = MockQuestion( MockTableAnswer(mock_df)) with pytest.raises(BatfishAssertException) as excinfo: assert_no_incompatible_ospf_sessions(nodes='nodes', remote_nodes='remote_nodes', session=bf) # Ensure found answer is printed assert mock_df.to_string() in str(excinfo.value) ospfSessionCompatibility.assert_called_with(nodes='nodes', remote_nodes='remote_nodes', statuses=UNESTABLISHED_OSPF_SESSION_STATUS_SPEC)
def init_bf_session(self): """ Initialize Batfish """ CURRENT_DIRECTORY = os.getcwd().split("/")[-1] NETWORK_NAME = config.batfish["network_name"] SNAPSHOT_NAME = config.batfish["snapshot_name"] SNAPSHOT_PATH = config.main["configs_directory"] bf_params = dict( host=config.batfish["address"], port_v1=config.batfish["port_v1"], port_v2=config.batfish["port_v2"], ssl=config.batfish["use_ssl"], ) if config.batfish["api_key"]: bf_params["api_key"] = config.batfish["api_key"] self.bf = Session.get("bf", **bf_params) self.bf.verify = False self.bf.set_network(NETWORK_NAME) self.bf.init_snapshot(SNAPSHOT_PATH, name=SNAPSHOT_NAME, overwrite=True) return True
def test_no_incompatible_bgp_sessions_from_session(): """Confirm no-incompatible-bgp-sessions assert passes and fails as expected when called from a session.""" bf = Session(load_questions=False) with patch.object(bf.q, 'bgpSessionCompatibility', create=True) as bgpSessionCompatibility: # Test success bgpSessionCompatibility.return_value = MockQuestion() bf.asserts.assert_no_incompatible_bgp_sessions(nodes='nodes', remote_nodes='remote_nodes', status='.*') bgpSessionCompatibility.assert_called_with(nodes='nodes', remote_nodes='remote_nodes', status='.*') # Test failure mock_df = DataFrame.from_records([{'Session': 'found', 'More': 'data'}]) bgpSessionCompatibility.return_value = MockQuestion( MockTableAnswer(mock_df)) with pytest.raises(BatfishAssertException) as excinfo: bf.asserts.assert_no_incompatible_bgp_sessions(nodes='nodes', remote_nodes='remote_nodes', status='.*') # Ensure found answer is printed assert mock_df.to_string() in str(excinfo.value) bgpSessionCompatibility.assert_called_with(nodes='nodes', remote_nodes='remote_nodes', status='.*')
def test_no_incompatible_ospf_sessions_from_session(): """Confirm no-incompatible-ospf-sessions assert passes and fails as expected when called from a session.""" bf = Session(load_questions=False) with patch.object(bf.q, "ospfSessionCompatibility", create=True) as ospfSessionCompatibility: # Test success ospfSessionCompatibility.return_value = MockQuestion() bf.asserts.assert_no_incompatible_ospf_sessions( nodes="nodes", remote_nodes="remote_nodes") ospfSessionCompatibility.assert_called_with( nodes="nodes", remote_nodes="remote_nodes", statuses=UNESTABLISHED_OSPF_SESSION_STATUS_SPEC, ) # Test failure mock_df = DataFrame.from_records([{ "Session": "found", "More": "data" }]) ospfSessionCompatibility.return_value = MockQuestion( MockTableAnswer(mock_df)) with pytest.raises(BatfishAssertException) as excinfo: bf.asserts.assert_no_incompatible_ospf_sessions( nodes="nodes", remote_nodes="remote_nodes") # Ensure found answer is printed assert mock_df.to_string() in str(excinfo.value) ospfSessionCompatibility.assert_called_with( nodes="nodes", remote_nodes="remote_nodes", statuses=UNESTABLISHED_OSPF_SESSION_STATUS_SPEC, )
def test_no_unestablished_bgp_sessions_from_session(): """Confirm no-uncompatible-bgp-sessions assert passes and fails as expected when called from a session.""" bf = Session(load_questions=False) with patch.object(bf.q, "bgpSessionStatus", create=True) as bgpSessionStatus: # Test success bgpSessionStatus.return_value = MockQuestion() bf.asserts.assert_no_unestablished_bgp_sessions( nodes="nodes", remote_nodes="remote_nodes") bgpSessionStatus.assert_called_with(nodes="nodes", remote_nodes="remote_nodes", status="NOT_ESTABLISHED") # Test failure mock_df = DataFrame.from_records([{ "Session": "found", "More": "data" }]) bgpSessionStatus.return_value = MockQuestion(MockTableAnswer(mock_df)) with pytest.raises(BatfishAssertException) as excinfo: bf.asserts.assert_no_unestablished_bgp_sessions( nodes="nodes", remote_nodes="remote_nodes") # Ensure found answer is printed assert mock_df.to_string() in str(excinfo.value) bgpSessionStatus.assert_called_with(nodes="nodes", remote_nodes="remote_nodes", status="NOT_ESTABLISHED")
def test_flows_succeed(): """Confirm flows-succeed assert passes and fails as expected when specifying a session.""" startLocation = "node1" headers = HeaderConstraints(srcIps="1.1.1.1") bf = Session(load_questions=False) with patch.object(bf.q, "reachability", create=True) as reachability: # Test success reachability.return_value = MockQuestion() assert_flows_succeed(startLocation, headers, session=bf) reachability.assert_called_with( pathConstraints=PathConstraints(startLocation=startLocation), headers=headers, actions="failure", ) # Test failure mock_df = DataFrame.from_records([{"Flow": "found", "More": "data"}]) reachability.return_value = MockQuestion(MockTableAnswer(mock_df)) with pytest.raises(BatfishAssertException) as excinfo: assert_flows_succeed(startLocation, headers, session=bf) # Ensure found answer is printed assert mock_df.to_string() in str(excinfo.value) reachability.assert_called_with( pathConstraints=PathConstraints(startLocation=startLocation), headers=headers, actions="failure", )
def test_no_incompatible_bgp_sessions(): """Confirm no-incompatible-bgp-sessions assert passes and fails as expected when specifying a session.""" bf = Session(load_questions=False) with patch.object(bf.q, "bgpSessionCompatibility", create=True) as bgpSessionCompatibility: # Test success bgpSessionCompatibility.return_value = MockQuestion() assert_no_incompatible_bgp_sessions(nodes="nodes", remote_nodes="remote_nodes", status=".*", session=bf) bgpSessionCompatibility.assert_called_with(nodes="nodes", remote_nodes="remote_nodes", status=".*") # Test failure mock_df = DataFrame.from_records([{ "Session": "found", "More": "data" }]) bgpSessionCompatibility.return_value = MockQuestion( MockTableAnswer(mock_df)) with pytest.raises(BatfishAssertException) as excinfo: assert_no_incompatible_bgp_sessions(nodes="nodes", remote_nodes="remote_nodes", status=".*", session=bf) # Ensure found answer is printed assert mock_df.to_string() in str(excinfo.value) bgpSessionCompatibility.assert_called_with(nodes="nodes", remote_nodes="remote_nodes", status=".*")
def test_filter_denies(): """Confirm filter-denies assert passes and fails as expected when specifying a session.""" headers = HeaderConstraints(srcIps='1.1.1.1') bf = Session(load_questions=False) with patch.object(bf.q, 'searchFilters', create=True) as mock_search_filters: # Test success mock_search_filters.return_value = MockQuestion() assert_filter_denies('filter', headers, session=bf) mock_search_filters.assert_called_with(filters='filter', headers=headers, action='permit') # Test failure; also test that startLocation is passed through mock_df = DataFrame.from_records([{'Flow': 'found', 'More': 'data'}]) mock_search_filters.return_value = MockQuestion( MockTableAnswer(mock_df)) with pytest.raises(BatfishAssertException) as excinfo: assert_filter_denies('filter', headers, startLocation='Ethernet1', session=bf) # Ensure found answer is printed assert mock_df.to_string() in str(excinfo.value) mock_search_filters.assert_called_with(filters='filter', headers=headers, startLocation='Ethernet1', action='permit')
def test_get_facts_questions(): """Test that get facts calls the right questions, passing through the right args.""" bf = Session(load_questions=False) nodes = "foo" with patch.object( bf.q, "nodeProperties", create=True) as mock_node, patch.object( bf.q, "interfaceProperties", create=True) as mock_iface, patch.object( bf.q, "bgpPeerConfiguration", create=True) as mock_peers, patch.object( bf.q, "bgpProcessConfiguration", create=True) as mock_proc, patch.object( bf.q, "ospfProcessConfiguration", create=True) as mock_ospf_proc, patch.object( bf.q, "ospfAreaConfiguration", create=True) as mock_ospf_area, patch.object( bf.q, "ospfInterfaceConfiguration", create=True) as mock_ospf_iface: mock_node.return_value = MockQuestion(MockTableAnswer) mock_iface.return_value = MockQuestion(MockTableAnswer) mock_proc.return_value = MockQuestion(MockTableAnswer) mock_peers.return_value = MockQuestion(MockTableAnswer) mock_ospf_proc.return_value = MockQuestion(MockTableAnswer) mock_ospf_area.return_value = MockQuestion(MockTableAnswer) mock_ospf_iface.return_value = MockQuestion(MockTableAnswer) get_facts(bf, nodes) mock_node.assert_called_with(nodes=nodes) mock_iface.assert_called_with(nodes=nodes) mock_proc.assert_called_with(nodes=nodes) mock_peers.assert_called_with(nodes=nodes) mock_ospf_proc.assert_called_with(nodes=nodes) mock_ospf_area.assert_called_with(nodes=nodes) mock_ospf_iface.assert_called_with(nodes=nodes)
def test_no_unestablished_bgp_sessions(): """Confirm no-uncompatible-bgp-sessions assert passes and fails as expected when specifying a session.""" bf = Session(load_questions=False) with patch.object(bf.q, 'bgpSessionStatus', create=True) as bgpSessionStatus: # Test success bgpSessionStatus.return_value = MockQuestion() assert_no_unestablished_bgp_sessions(nodes='nodes', remote_nodes='remote_nodes', session=bf) bgpSessionStatus.assert_called_with(nodes='nodes', remote_nodes='remote_nodes', status="NOT_ESTABLISHED") # Test failure mock_df = DataFrame.from_records([{'Session': 'found', 'More': 'data'}]) bgpSessionStatus.return_value = MockQuestion( MockTableAnswer(mock_df)) with pytest.raises(BatfishAssertException) as excinfo: assert_no_unestablished_bgp_sessions(nodes='nodes', remote_nodes='remote_nodes', session=bf) # Ensure found answer is printed assert mock_df.to_string() in str(excinfo.value) bgpSessionStatus.assert_called_with(nodes='nodes', remote_nodes='remote_nodes', status="NOT_ESTABLISHED")
def test_flows_succeed_from_session(): """Confirm flows-succeed assert passes and fails as expected when called from a session.""" startLocation = "node1" headers = HeaderConstraints(srcIps='1.1.1.1') bf = Session(load_questions=False) with patch.object(bf.q, 'reachability', create=True) as reachability: # Test success reachability.return_value = MockQuestion() bf.asserts.assert_flows_succeed(startLocation, headers) reachability.assert_called_with( pathConstraints=PathConstraints(startLocation=startLocation), headers=headers, actions='failure') # Test failure mock_df = DataFrame.from_records([{'Flow': 'found', 'More': 'data'}]) reachability.return_value = MockQuestion( MockTableAnswer(mock_df)) with pytest.raises(BatfishAssertException) as excinfo: bf.asserts.assert_flows_succeed(startLocation, headers) # Ensure found answer is printed assert mock_df.to_string() in str(excinfo.value) reachability.assert_called_with( pathConstraints=PathConstraints(startLocation=startLocation), headers=headers, actions='failure')
def test_get_session(): """Confirm Session object is built for a specified session type.""" session_host = "foobar" session = Session.get(type_="bf", load_questions=False, host=session_host) # Confirm the session is the correct type assert isinstance(session, Session) # Confirm params were passed through assert session.host == session_host
def test_get_session_default(): """Confirm default Session object is built when no type is specified.""" session_host = "foobar" session = Session.get(load_questions=False, host=session_host) # Confirm the session is the correct type assert isinstance(session, Session) # Confirm params were passed through assert session.host == session_host
def session(): s = Session() # Snapshot which can be referenced by name other_name = s.init_snapshot(join(_this_dir, 'snapshots', 'fact_snapshot2')) # Current snapshot name = s.init_snapshot(join(_this_dir, 'snapshots', 'fact_snapshot')) yield s s.delete_snapshot(name) s.delete_snapshot(other_name)
def session(): s = Session() # Snapshot which can be referenced by name other_name = s.init_snapshot( join(_this_dir, "snapshots", "fact_snapshot2"), _PREVIOUS_SNAPSHOT) # Current snapshot name = s.init_snapshot(join(_this_dir, "snapshots", "fact_snapshot"), _CURRENT_SNAPSHOT) yield s s.delete_snapshot(name) s.delete_snapshot(other_name)
def test_get_facts_questions_specific_snapshot(): """Test that get facts calls the right questions, passing through the right args when a snapshot is specified.""" bf = Session(load_questions=False) nodes = "foo" with patch.object( bf.q, "nodeProperties", create=True) as mock_node, patch.object( bf.q, "interfaceProperties", create=True) as mock_iface, patch.object( bf.q, "bgpPeerConfiguration", create=True) as mock_peers, patch.object( bf.q, "bgpProcessConfiguration", create=True) as mock_proc, patch.object( bf.q, "ospfProcessConfiguration", create=True) as mock_ospf_proc, patch.object( bf.q, "ospfAreaConfiguration", create=True) as mock_ospf_area, patch.object( bf.q, "ospfInterfaceConfiguration", create=True) as mock_ospf_iface: # Setup mock answers for each underlying question mock_node_a = Mock(return_value=MockTableAnswer()) mock_iface_a = Mock(return_value=MockTableAnswer()) mock_proc_a = Mock(return_value=MockTableAnswer()) mock_peers_a = Mock(return_value=MockTableAnswer()) mock_ospf_proc_a = Mock(return_value=MockTableAnswer()) mock_ospf_area_a = Mock(return_value=MockTableAnswer()) mock_ospf_iface_a = Mock(return_value=MockTableAnswer()) # Setup mock questions for all underlying questions mock_node.return_value = MockQuestion(mock_node_a) mock_iface.return_value = MockQuestion(mock_iface_a) mock_proc.return_value = MockQuestion(mock_proc_a) mock_peers.return_value = MockQuestion(mock_peers_a) mock_ospf_proc.return_value = MockQuestion(mock_ospf_proc_a) mock_ospf_area.return_value = MockQuestion(mock_ospf_area_a) mock_ospf_iface.return_value = MockQuestion(mock_ospf_iface_a) get_facts(bf, nodes, snapshot="snapshot") # Make sure questions were all called with expected params mock_node.assert_called_with(nodes=nodes) mock_iface.assert_called_with(nodes=nodes) mock_proc.assert_called_with(nodes=nodes) mock_peers.assert_called_with(nodes=nodes) mock_ospf_proc.assert_called_with(nodes=nodes) mock_ospf_area.assert_called_with(nodes=nodes) mock_ospf_iface.assert_called_with(nodes=nodes) # Make sure answer functions were all called with expected params mock_node_a.assert_called_with(snapshot="snapshot") mock_iface_a.assert_called_with(snapshot="snapshot") mock_proc_a.assert_called_with(snapshot="snapshot") mock_peers_a.assert_called_with(snapshot="snapshot") mock_ospf_proc_a.assert_called_with(snapshot="snapshot") mock_ospf_area_a.assert_called_with(snapshot="snapshot") mock_ospf_iface_a.assert_called_with(snapshot="snapshot")
def test_run_assertion(): """Confirm running passing assertion results in a passing message.""" bf = Session(load_questions=False) assertion = { 'name': 'assert_name', 'type': 'assert_no_undefined_references', } with patch.object(bf.q, 'undefinedReferences', create=True) as mock_undef: mock_undef.return_value = MockQuestion(MockTableAnswer()) assert run_assertion(bf, assertion) == ASSERT_PASS_MESSAGE
def test_upload_diagnostics_metadata(): """Confirm metadata file is generated with correct content.""" metadata = {"test_key1": "test_value", "test_key2": 1234} out_dir = upload_diagnostics( Session(load_questions=False), metadata, dry_run=True, questions=[] ) with open(os.path.join(out_dir, METADATA_FILENAME)) as f: contents = json.loads(f.read()) assert contents == metadata
def test_print_workstatus_old_task(logger, caplog): session = Session(logger) session.stale_timeout = 5 nowFunction = lambda tzinfo: datetime.datetime(2017, 12, 20, 0, 0, 0, 0, tzinfo=tzinfo) workStatus = "TEST" taskDetails = json.dumps({ "obtained": "2017-12-20 00:00:00 UTC", "batches": [{ "completed": 0, "description": "Fooing the bar", "size": 0, "startDate": "2016-11-22 10:43:21 UTC" }] }) _print_work_status(session, workStatus, taskDetails, nowFunction) assert "status: TEST" in caplog.text assert ".... {obtained} Fooing the bar Elapsed 1y27d13:16:39".format( obtained=_print_timestamp( _parse_timestamp(json.loads(taskDetails)["obtained"]))) \ in caplog.text