Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Python testing scripts and utilities - Part 1 #3855

Merged
merged 6 commits into from
Jan 31, 2023

Conversation

fruffy
Copy link
Collaborator

@fruffy fruffy commented Jan 23, 2023

  • Replace the custom defined "outputs" with an actual logger that prints and logs to a file as needed
  • Use modern Python3 code (f-strings, pathlib, etc)
  • Use subprocess.run instead of opening a process than running it.

@fruffy fruffy force-pushed the fruffy/refactor_testing_scripts branch 4 times, most recently from 685147d to 492d22b Compare January 24, 2023 16:38
@fruffy fruffy marked this pull request as ready for review January 24, 2023 19:47
@fruffy
Copy link
Collaborator Author

fruffy commented Jan 24, 2023

@vlstill This is a big PR, because it refreshes a lot of the old Python code. Still, among others, it refactors the test utilities to use subprocess.run instead of check_output etc.

After this PR, I am planning to generalize ebpfenv, such that it can be used as a general virtual namespace environment. Finally, add typing information to all the Python utilities. You had some comments on the PTF PR, are those resolved or do you have any other suggestions?

@fruffy
Copy link
Collaborator Author

fruffy commented Jan 24, 2023

@mbudiu-vmw This PR makes a lot of changes in the testutils library and migrates to actual logging for the test scripts from the custom logging that we had. It does not touch the Python scripts which do not depend on testutils, such as run-bmv2-test.py etc.

@tatry @osinstom This PR touches ubpf scripts, too. Any dependencies I should keep in mind there?

import random
import logging
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will let the owners of this file review the changes

Copy link
Collaborator Author

@fruffy fruffy Jan 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's us! We approve :)

try:
result = process_file(options, argv)
except Exception as e:
print("Exception ", e)
sys.exit(FAILURE)
print(f"There was a problem parsing STF file {options.testFile}:")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this always a parsing problem?

# Actual location of the test framework
self.testdir = os.path.dirname(os.path.realpath(__file__))
self.extern = "" # Path to C file with extern definition
self.binary = "" # This program's name.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find the original version easier to read. Why spend time reformatting whitespace?

import sys
from pathlib import Path
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this file even used?

import sys
from subprocess import Popen, PIPE
import logging
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will let the owners review this file

@@ -40,7 +40,8 @@ p4tools_add_xfail_reason(

p4tools_add_xfail_reason(
"testgen-p4c-bmv2-ptf"
"Invalid reference to object of type"
"Segmentation fault"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a good sign.
I see no reason for the changes in the test scripts to lead to a segfault, something must be wrong somewhere.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In both cases the segmentation fault is thrown.

The underlying cause is a bit tricky. Previously, simple_switch_grpc was invoked with --log-console, which directly printed output to stdout/err. However, this occasionally overwhelmed the process pipe and the process got stuck.

Now, we use --log-file, but simple switch crashes before the statement can be logged/generated. So it does not appear anymore.

The completely solution is to either fix simple_switch's logging or to fix the Popen call so that it does not get stuck.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's the same bug please file an issue and add a comment to the makefile.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not aware of a corresponding bug for p4c, we should have one. Can you please add one?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I asked Antonin to migrate the issue.

Copy link
Contributor

@vlstill vlstill left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying primarily to look at the Python side of the change, I did not check overall design. I think this goes in the right direction and I have a few suggestions in the code.

I'd suggest running the code through some python formatting checker such as pycodestyle and possibly through flake8 (linter). I think that for languages that have specified code style, it generally makes sense to adhere to it (even though I might personally disagree with some python style decisions).

FILE_DIR = Path(__file__).resolve().parent
TOOLS_PATH = FILE_DIR.joinpath("../../tools")
sys.path.append(str(TOOLS_PATH))
import testutils
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a comment that this import needs the path modification?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really dislike this boilerplate code actually. Do you have a better idea how to handle relative parent-level imports? Without requiring the user to input the path every time.

Comment on lines -36 to +42
return partial(self.func, instance, *(self.args or ()),
**(self.keywords or {}))
return partial(self.func, instance, *(self.args or ()), **(self.keywords or {}))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This (and similar changes) now goes over the 79 character limit of Python's formating conventions. I don't think that is a good idea, many (at least semi-intelligent) code editors will highlight that as a problem. If we want to go against some of the python style guides, I think we should have an override file that informs pycodestyle and similar programs what is to be ignored.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have been using a .yapf.style and a .pylintrc file with a character limit set to 100. I used 100 because our C code also uses 100 as character limit. I can add this file and its formatting in a separate PR?

I have been not using black since it is a little too opinionated. There are so many options for style tools, I am actually not sure which we should use.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Is there any reason to not add the style config files in this PR?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is already big, so I was hoping to do the formatting in a separate PR. Then we can also agree on a style there.

@@ -246,22 +248,19 @@ def __exit__(self, exc_type, exc_value, tb):
if not issubclass(exc_type, P4RuntimeWriteException):
# let unexpected exceptions pass through
return False
self.exception = exc_value # store for later retrieval
self.exception = exc_value # store for later retrieval
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this was formatted according to the python style guide (at least two spaces before comment) and now goes directly against it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having formatting that complies with Mihai's request and the two space rule is unfortunately quite difficult. I have not been able to find a configuration that does both (Aligning comments as well as maintaining a minimum distance).

Personally, I prefer to have no inline comments at all since they often run over the maximum character length.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

google/yapf#675

This is the issue I am facing. But other formatters are also not better at this. It might be less headache to forbid inline comments in general.

def ByteToHex(byteStr):
return ''.join( [ ("%02X" % x) for x in byteStr ] )
return ''.join([("%02X" % x) for x in byteStr])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return ''.join([("%02X" % x) for x in byteStr])
return ''.join(("%02X" % x) for x in byteStr)

(join can accept an iterator expression directly)

@@ -249,13 +282,14 @@ def makeMask(self, value):
value = value[2:]
prefix = "0o"
else:
raise Exception("Decimal value "+value+" not supported for ternary key")
raise Exception("Decimal value " + value + " not supported for ternary key")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or

Suggested change
raise Exception("Decimal value " + value + " not supported for ternary key")
raise Exception(f"Decimal value {value} not supported for ternary key")

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not touched bmv2stf.py yet except for a little formatting. The code is very old and written for Python 2.7. I would like to do this in a separate PR.

backends/ebpf/targets/target.py Outdated Show resolved Hide resolved
# If the compiler crashed fail the test
if 'Compiler Bug' in open(self.outputs["stderr"]).readlines():
sys.exit(FAILURE)
if "Compiler Bug" in str(out):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is out binary?

tools/testutils.py Outdated Show resolved Hide resolved
return proc


def run_process(verbose, proc, timeout, outputs, errmsg):

def run_process(proc, timeout, errmsg):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name is a bit misleading, it suggest the process is executed, but in fact only its outputs are consumed.

tools/testutils.py Outdated Show resolved Hide resolved
@osinstom
Copy link
Contributor

@fruffy it's been a while since we worked on the uBPF backend, but there should not be any specific dependencies to be aware of.

@fruffy fruffy force-pushed the fruffy/refactor_testing_scripts branch 2 times, most recently from 770b0b2 to 20143f1 Compare January 25, 2023 14:46
@fruffy fruffy force-pushed the fruffy/refactor_testing_scripts branch from 20143f1 to ece0074 Compare January 26, 2023 15:44
@fruffy
Copy link
Collaborator Author

fruffy commented Jan 30, 2023

@mbudiu-vmw Any concerns on your side that have not been resolved yet?

@mihaibudiu
Copy link
Contributor

This is not my favorite part of the compiler, so I try to avoid it. If you promise to take care of it, it's yours.

@fruffy
Copy link
Collaborator Author

fruffy commented Jan 31, 2023

This is not my favorite part of the compiler, so I try to avoid it. If you promise to take care of it, it's yours.

Thanks! A lot of the code that was touched in this PR I have written at some point, so I am on the hook anyway.

@fruffy fruffy merged commit 64285c4 into main Jan 31, 2023
@fruffy fruffy deleted the fruffy/refactor_testing_scripts branch January 31, 2023 17:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants