% Regression tests for isotpscanner
~ vcan_socket needs_root linux not_pypy automotive_comm


+ Configuration
~ conf

= Imports
with open(scapy_path("test/contrib/automotive/interface_mockup.py")) as f:
    exec(f.read())

ISOTPSocket = ISOTPSoftSocket


+ Usage tests

= Test wrong usage

result = subprocess.Popen([sys.executable, "scapy/tools/automotive/isotpscanner.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

std_out, std_err = result.communicate()
if result.returncode:
    print(std_out)
    print(std_err)

assert result.returncode != 0

expected_output = plain_str(b'usage:')
assert expected_output in plain_str(std_err)


= Test show help

result = subprocess.Popen([sys.executable, "scapy/tools/automotive/isotpscanner.py", "--help"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
std_out, _ = result.communicate()
expected_output = plain_str(b'Scan for open ISOTP-Sockets.')

assert result.wait() == 0
assert expected_output in plain_str(std_out)


= Test wrong socket for Python2 or Windows

if six.PY2:
    version = subprocess.Popen(["python2", "--version"], stdout=subprocess.PIPE)
    if 0 == version.wait():
        print(version.communicate())
    result = subprocess.Popen([sys.executable, "scapy/tools/automotive/isotpscanner.py", "-c", iface0, "-s", "0x600", "-e", "0x600"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    expected_output = plain_str(b'Please provide all required arguments.')
    std_out, std_err = result.communicate()
    assert result.wait() == 1
    assert expected_output in plain_str(std_err)


= Test Python2 call

result = subprocess.Popen([sys.executable, "scapy/tools/automotive/isotpscanner.py", "-i", "socketcan", "-c", iface0, "-s", "0x600", "-e", "0x600", "-v"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
returncode = result.wait()
expected_output = plain_str(b'Start scan')
std_out, std_err = result.communicate()

assert returncode == 0
assert expected_output in plain_str(std_out)

= Test Python2 call with one python-can arg

result = subprocess.Popen([sys.executable, "scapy/tools/automotive/isotpscanner.py", "-i", "socketcan", "-c", iface0, "-a", "bitrate=500000", "-s", "0x600", "-e", "0x600", "-v"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
returncode = result.wait()
expected_output = plain_str(b'Start scan')
std_out, std_err = result.communicate()

assert returncode == 0
assert expected_output in plain_str(std_out)


= Test Python2 call with multiple python-can args

result = subprocess.Popen([sys.executable, "scapy/tools/automotive/isotpscanner.py", "-i", "socketcan", "-c", iface0, "-a", "bitrate=500000 receive_own_messages=True", "-s", "0x600", "-e", "0x600", "-v"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
returncode = result.wait()
expected_output = plain_str(b'Start scan')
std_out, std_err = result.communicate()

assert returncode == 0
assert expected_output in plain_str(std_out)

= Test Python2 call with multiple python-can args 2

result = subprocess.Popen([sys.executable, "scapy/tools/automotive/isotpscanner.py", "-i", "socketcan", "-c", iface0, "--python-can_args", "bitrate=500000 receive_own_messages=True", "-s", "0x600", "-e", "0x600", "-v"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
returncode = result.wait()
expected_output = plain_str(b'Start scan')
std_out, std_err = result.communicate()

assert returncode == 0
assert expected_output in plain_str(std_out)


+ Scan tests

= Test standard scan

drain_bus(iface0)
started = threading.Event()

def isotpserver():
    with new_can_socket(iface0) as isocan, ISOTPSocket(isocan, sid=0x700, did=0x600) as s:
        s.sniff(timeout=200, count=1, started_callback=started.set)

sniffer = threading.Thread(target=isotpserver)
sniffer.start()
started.wait(timeout=10)

result = subprocess.Popen([sys.executable, "scapy/tools/automotive/isotpscanner.py"] + can_socket_string_list + ["-s", "0x600", "-e", "0x600"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
returncode1 = result.wait()
std_out1, std_err1 = result.communicate()
result = subprocess.Popen([sys.executable, "scapy/tools/automotive/isotpscanner.py"] + can_socket_string_list + ["-s", "0x600", "-e", "0x600"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
returncode2 = result.wait()
std_out2, std_err2 = result.communicate()

send_returncode = subprocess.call(['cansend', iface0, '600#01aa'])
sniffer.join(timeout=10)

assert 0 == send_returncode
assert returncode1 == 0
assert returncode2 == 0

expected_output = [b'0x600', b'0x700']
for out in expected_output:
    assert plain_str(out) in plain_str(std_out1 + std_out2)


= Test extended scan

drain_bus(iface0)
started = threading.Event()

def isotpserver():
    with new_can_socket0() as isocan, ISOTPSocket(isocan, sid=0x700, did=0x601, extended_addr=0xaa, extended_rx_addr=0xbb) as s:
        s.sniff(timeout=200, count=1, started_callback=started.set)

sniffer = threading.Thread(target=isotpserver)
sniffer.start()
started.wait(timeout=10)

result = subprocess.Popen([sys.executable, "scapy/tools/automotive/isotpscanner.py"] + can_socket_string_list + ["-s", "0x601", "-e", "0x601", "-x"], stdout=subprocess.PIPE)
returncode1 = result.wait()
std_out1, std_err1 = result.communicate()
result = subprocess.Popen([sys.executable, "scapy/tools/automotive/isotpscanner.py"] + can_socket_string_list + ["-s", "0x601", "-e", "0x601", "-x"], stdout=subprocess.PIPE)
returncode2 = result.wait()
std_out2, std_err2 = result.communicate()

send_returncode = subprocess.call(['cansend', iface0, '601#BB01aa'])
sniffer.join(timeout=10)

expected_output = [b'0x601', b'0xbb', b'0x700', b'0xaa']
assert 0 == send_returncode
assert returncode1 == 0
assert returncode2 == 0

for out in expected_output:
    assert plain_str(out) in plain_str(std_out1 + std_out2)

= Test extended only scan

drain_bus(iface0)
started = threading.Event()

def isotpserver():
    with new_can_socket0() as isocan, ISOTPSocket(isocan, sid=0x700, did=0x601, extended_addr=0xaa, extended_rx_addr=0xbb) as s:
        s.sniff(timeout=200, count=1, started_callback=started.set)

sniffer = threading.Thread(target=isotpserver)
sniffer.start()
started.wait(timeout=10)

result = subprocess.Popen([sys.executable, "scapy/tools/automotive/isotpscanner.py"] + can_socket_string_list + ["-s", "0x601", "-e", "0x601", "-x"], stdout=subprocess.PIPE)
returncode1 = result.wait()
std_out1, std_err1 = result.communicate()
result = subprocess.Popen([sys.executable, "scapy/tools/automotive/isotpscanner.py"] + can_socket_string_list + ["-s", "0x601", "-e", "0x601", "-x"], stdout=subprocess.PIPE)
returncode2 = result.wait()
std_out2, std_err2 = result.communicate()

send_returncode = subprocess.call(['cansend', iface0, '601#BB01aa'])
sniffer.join(timeout=10)

expected_output = [b'0x601', b'0xbb', b'0x700', b'0xaa']
assert 0 == send_returncode
assert returncode1 == 0
assert returncode2 == 0

for out in expected_output:
    assert plain_str(out) in plain_str(std_out1 + std_out2)


= Test scan with piso flag

drain_bus(iface0)
started = threading.Event()

def isotpserver():
    with new_can_socket0() as isocan, ISOTPSocket(isocan, sid=0x700, did=0x601, extended_addr=0xaa, extended_rx_addr=0xbb) as s:
        s.sniff(timeout=200, count=1, started_callback=started.set)

sniffer = threading.Thread(target=isotpserver)
sniffer.start()
started.wait(timeout=10)

result = subprocess.Popen([sys.executable, "scapy/tools/automotive/isotpscanner.py"] + can_socket_string_list + ["-s", "0x601", "-e", "0x601", "-x", "-C"], stdout=subprocess.PIPE)
returncode1 = result.wait()
std_out1, std_err1 = result.communicate()

result = subprocess.Popen([sys.executable, "scapy/tools/automotive/isotpscanner.py"] + can_socket_string_list + ["-s", "0x601", "-e", "0x601", "-x", "-C"], stdout=subprocess.PIPE)
returncode2 = result.wait()
std_out2, std_err2 = result.communicate()

send_returncode = subprocess.call(['cansend', iface0, '601#BB01aa'])
sniffer.join(timeout=10)

assert 0 == send_returncode
assert returncode1 == 0 == returncode2

expected_output = [b'sid=0x601', b'did=0x700', b'padding=False', b'extended_addr=0xbb', b'extended_rx_addr=0xaa']

for out in expected_output:
    assert plain_str(out) in plain_str(std_out1 + std_out2)


+ Cleanup

= Delete vcan interfaces

assert cleanup_interfaces()
