File: test_response.py

package info (click to toggle)
python-scrapli 2023.7.30-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,536 kB
  • sloc: python: 14,459; makefile: 72
file content (229 lines) | stat: -rw-r--r-- 8,950 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
import sys
from datetime import datetime

import pytest

from scrapli.exceptions import ScrapliCommandFailure
from scrapli.helper import _textfsm_get_template
from scrapli.response import MultiResponse, Response


def test_response_init():
    response = Response("localhost", "ls -al", failed_when_contains="tacocat")
    response_start_time = str(datetime.now())[:-7]
    assert response.host == "localhost"
    assert response.channel_input == "ls -al"
    assert str(response.start_time)[:-7] == response_start_time
    assert response.failed is True
    assert bool(response) is True
    assert (
        repr(response)
        == "Response(host='localhost',channel_input='ls -al',textfsm_platform='',genie_platform='',failed_when_contains=['tacocat'])"
    )
    assert str(response) == "Response <Success: False>"
    assert response.failed_when_contains == ["tacocat"]
    with pytest.raises(ScrapliCommandFailure):
        response.raise_for_status()


def test_multi_response():
    host = "localhost"
    response1 = Response(host, "ls -al")
    response2 = Response(host, "ls -al")
    multi_response = MultiResponse()
    assert multi_response.host == ""
    multi_response.extend([response1, response2])
    assert len(multi_response) == 2
    assert multi_response.failed is True
    assert (
        repr(multi_response)
        == "[Response(host='localhost',channel_input='ls -al',textfsm_platform='',genie_platform='',failed_when_contains=None), Response(host='localhost',channel_input='ls -al',textfsm_platform='',genie_platform='',failed_when_contains=None)]"
    )
    assert str(multi_response) == "MultiResponse <Success: False; Response Elements: 2>"
    with pytest.raises(ScrapliCommandFailure):
        multi_response.raise_for_status()
    multi_response[0].failed = False
    multi_response[1].failed = False
    assert multi_response.failed is False
    assert multi_response.raise_for_status() is None
    assert multi_response.host == host
    assert (
        repr(multi_response)
        == "[Response(host='localhost',channel_input='ls -al',textfsm_platform='',genie_platform='',failed_when_contains=None), Response(host='localhost',channel_input='ls -al',textfsm_platform='',genie_platform='',failed_when_contains=None)]"
    )
    assert str(multi_response) == "MultiResponse <Success: True; Response Elements: 2>"
    assert multi_response.result == "ls -al\nls -al\n"


def test_response_record_result():
    response = Response("localhost", "ls -al")
    response_end_time = str(datetime.now())[:-7]
    response_bytes = b"""
ls -al
total 264
drwxr-xr-x  34 carl  staff   1088 Jan 27 19:07 ./
drwxr-xr-x  21 carl  staff    672 Jan 25 15:56 ../
-rw-r--r--   1 carl  staff  53248 Jan 27 19:07 .coverage
drwxr-xr-x  12 carl  staff    384 Jan 27 19:13 .git/"""
    response.record_response(response_bytes)
    assert str(response.finish_time)[:-7] == response_end_time
    assert response.result == response_bytes.decode()
    assert response.failed is False


def test_response_record_result_failed_when_failed():
    response = Response("localhost", "ls -al", failed_when_contains=["!racecar!"])
    response_end_time = str(datetime.now())[:-7]
    response_bytes = b"""
ls -al
total 264
drwxr-xr-x  34 carl  staff   1088 Jan 27 19:07 ./
drwxr-xr-x  21 carl  staff    672 Jan 25 15:56 ../
-rw-r--r--   1 carl  staff  53248 Jan 27 19:07 !racecar!
drwxr-xr-x  12 carl  staff    384 Jan 27 19:13 .git/"""
    response.record_response(response_bytes)
    assert str(response.finish_time)[:-7] == response_end_time
    assert response.result == response_bytes.decode()
    assert response.failed is True


def test_response_record_result_failed_when_success():
    response = Response("localhost", "ls -al", failed_when_contains=["!racecar!"])
    response_end_time = str(datetime.now())[:-7]
    response_bytes = b"""
ls -al
total 264
drwxr-xr-x  34 carl  staff   1088 Jan 27 19:07 ./
drwxr-xr-x  21 carl  staff    672 Jan 25 15:56 ../
-rw-r--r--   1 carl  staff  53248 Jan 27 19:07 .coverage
drwxr-xr-x  12 carl  staff    384 Jan 27 19:13 .git/"""
    response.record_response(response_bytes)
    assert str(response.finish_time)[:-7] == response_end_time
    assert response.result == response_bytes.decode()
    assert response.failed is False


@pytest.mark.parametrize(
    "parse_type",
    [
        (
            False,
            ["Internet", "172.31.254.1", "-", "0000.0c07.acfe", "ARPA", "Vlan254"],
        ),
        (
            True,
            {
                "protocol": "Internet",
                "address": "172.31.254.1",
                "age": "-",
                "mac": "0000.0c07.acfe",
                "type": "ARPA",
                "interface": "Vlan254",
            },
        ),
    ],
    ids=["to_dict_false", "to_dict_true"],
)
def test_response_parse_textfsm(parse_type):
    to_dict = parse_type[0]
    expected_result = parse_type[1]
    response = Response("localhost", channel_input="show ip arp", textfsm_platform="cisco_ios")
    response_bytes = b"""Protocol  Address          Age (min)  Hardware Addr   Type   Interface
Internet  172.31.254.1            -   0000.0c07.acfe  ARPA   Vlan254
Internet  172.31.254.2            -   c800.84b2.e9c2  ARPA   Vlan254
"""
    response.record_response(response_bytes)
    assert response.textfsm_parse_output(to_dict=to_dict)[0] == expected_result


def test_response_parse_textfsm_string_path():
    template = _textfsm_get_template("cisco_ios", "show ip arp").name
    response = Response("localhost", channel_input="show ip arp", textfsm_platform="cisco_ios")
    response_bytes = b"""Protocol  Address          Age (min)  Hardware Addr   Type   Interface
Internet  172.31.254.1            -   0000.0c07.acfe  ARPA   Vlan254
Internet  172.31.254.2            -   c800.84b2.e9c2  ARPA   Vlan254
"""
    response.record_response(response_bytes)
    result = response.textfsm_parse_output(template=template)
    assert result[0]["address"] == "172.31.254.1"


def test_response_parse_textfsm_fail():
    response = Response("localhost", channel_input="show ip arp", textfsm_platform="cisco_ios")
    response_bytes = b""
    response.record_response(response_bytes)
    assert response.textfsm_parse_output() == []


def test_response_parse_textfsm_no_template():
    response = Response("localhost", channel_input="show ip arp", textfsm_platform="potato")
    response_bytes = b""
    response.record_response(response_bytes)
    assert response.textfsm_parse_output() == []


@pytest.mark.skipif(
    sys.version_info.minor > 10, reason="genie not currently available for python 3.11"
)
def test_response_parse_genie():
    response = Response("localhost", channel_input="show ip arp", genie_platform="iosxe")
    response_bytes = b"""Protocol  Address          Age (min)  Hardware Addr   Type   Interface
Internet  172.31.254.1            -   0000.0c07.acfe  ARPA   Vlan254
Internet  172.31.254.2            -   c800.84b2.e9c2  ARPA   Vlan254
"""
    response.record_response(response_bytes)
    result = response.genie_parse_output()
    assert (
        result["interfaces"]["Vlan254"]["ipv4"]["neighbors"]["172.31.254.1"]["ip"] == "172.31.254.1"
    )


@pytest.mark.skipif(
    sys.version_info.minor > 10, reason="genie not currently available for python 3.11"
)
def test_response_parse_genie_fail():
    response = Response("localhost", channel_input="show ip arp", genie_platform="iosxe")
    response_bytes = b""
    response.record_response(response_bytes)
    assert response.genie_parse_output() == []


def test_response_parse_ttp():
    response = Response("localhost", channel_input="show ip arp", genie_platform="iosxe")

    # example data lifted straight out of ttp docs
    ttp_template = """
    interface {{ interface }}
     ip address {{ ip }}/{{ mask }}
     description {{ description }}
     ip vrf {{ vrf }}
    """

    response_bytes = b"""    interface Loopback0
     description Router-id-loopback
     ip address 192.168.0.113/24
    !
    interface Vlan778
     description CPE_Acces_Vlan
     ip address 2002::fd37/124
     ip vrf CPE1
    !
"""
    response.record_response(response_bytes)
    result = response.ttp_parse_output(template=ttp_template)
    assert result[0][0]["ip"] == "192.168.0.113"


def test_response_parse_ttp_fail():
    response = Response("localhost", channel_input="show ip arp", genie_platform="iosxe")
    response_bytes = b""
    response.record_response(response_bytes)
    assert response.ttp_parse_output(template="blah") == [{}]


def test_record_response_unicodedecodeerror():
    # this test validates that we catch unicdedecodeerror when decoding raw result
    response = Response("localhost", channel_input="show ip arp", genie_platform="iosxe")
    response_bytes = b"Manufacturer name :p\xb67\x038\x93\xa5\x03\x10\n"
    response.record_response(response_bytes)
    assert repr(response.result) == "'Manufacturer name :p¶7\\x038\\x93¥\\x03\\x10\\n'"