-
Notifications
You must be signed in to change notification settings - Fork 106
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
Execution.CheckFilter implementation when 2000 test cases are exceeded #1117
Comments
Sure, this could be improved
Not sure I understand the issue here, nor the workaround. Isn't the most easy way just set the AssemblySelectLimit to a very high number ? That eliminates the logic. |
@jjachimowicz Any comments? |
@OsirisTerje I'll get back to you soon. |
This took a bit longer than anticipated but @cyanite and I gave this a look and we think we have an idea how this can be fixed. We will create a pull request based on our findings and assumptions. |
Before you raise that PR, please explain what you're thinking, also respond to my comment above. And, what do you mean by "raw filter" ? |
Hi @OsirisTerje, (FYI, me and @jjachimowicz are colleagues; we debugged this together.) Here is how the adapter behaves currently (on master), when invoked from dotnet test. We start test with e.g. The adapter then does the following. Method names in parenthesis, * means overridden for the non-IDE case.
So the end result is that all filters get converted into, usually much longer, filters with a list of cases except I don't understand why this would be desired. As I understand it, the test length check is to avoid passing in too We instead propose this flow (referencing the steps above):
Note that all this only covers the dotnet-test flow (non-IDE mode). For the IDE-mode, nothing will change (although there is some redundant work there, which we also address in the PR). |
Appreciate your efforts here! I believe that what you're looking at is the code here: Your 6 => A in the image, 7 => B and 8 => C. I don't remember exactly the reason for the code in C. So it might be worth a try to change this to return the original filter instead. B is the handling of explicits, which you suggest to remove, but that would remove the explicit handling, so that's a no-go. The filter in your case from discovery should be something like this: Also, the check at A and B should then be something else than IsCategory, also covering for other short filters. I need to look more at the tokenizer to see what each of the VSTest filters is being translated to. Note that we have had situations with extremely long VSTest filters too, so it is not a case of just looking at the existence of such a filter. This is also a part of the code that have been (earlier) very hard to test. So as part of any changes here, there need to be a better test suite to cover all changes. There are tests in the Acceptance tests that could be extended to cover all situations, that is one solution to the test issue at hand. This code has evolved over a decade, and there are multiple different situations that needs to be considered. Any change should be as small as possible, and thoroughly tested. We have also discussed whether we really need the discovery phase at all, but the work involved to ensure the adapter works without it has been too much. |
No no, I don't. My step 6 retains that logic unchanged. As for your "A", that's my step 5. This step doesn't trigger if you, for instance, provide a filter that doesn't enumerate any tests (but this is a separate point, and I don't propose to fix or change that; also retained.)
In this code path, all filters will come from the command line, so how aren't they all short? If they are long, it's because someone explicitly provided a long filter on the command line. Filters that come from Visual Studio doesn't contain categories and similar, only test cases.
Right, but since people explicitly chose to provide a long filter, I don't see how it's NUnit's job to "shorten" it (by removing it). If it performs poorly, people should provide shorter filters. Also, the current code actually makes many filters much longer due to step 8. Also, the check implemented currently in step 6 isn't about the filter at all: It's about the number of tests the filter discovers. It can be the smallest filter in the world, but since it'll discover many tests, the adapter decides to clear it. Edit: Here is the commit (proposed PR), for reference: edlund-as@4cf4b5a please ignore the .gitattributes part :) |
Actually, there are tools that do this, e.g. Jetbrain's TeamCity have a feature which does this (we have a separate issue around that). So, no, it might not be the user itself, we simply don't know. All we see is a long list. Looking at the code, I am not sure why you do what you do. I might misunderstand what the pieces are intended to do though.
Can you add some tests to check where this is actually ending up? I understand it might solve your immediate problem, but wouldn't it be better to just allow more filters than a category filter to be excluded from the assemblyselectlimit? One could add a property to the testfilter that sets what kind of filter has been applied, and use that to check whether it can be forwarded or not. |
Right, ok. But as I tried to explain, the current filter limiter doesn't look at the filter at all, but only on the number of tests it results in. It doesn't seem to make much sense, since short filters can, and often do, result in many cases. So if you really want to avoid long filters in that situation, I suppose look at the textual or structural length. Because when you say "All we see is a long list", no we don't. We see a filter. The long list comes from our own discovery, and there is no reason for us to turn that into a list at all, since we have the original filter.
Not in any way that matters. After the simplifications, those two code paths become the same in some cases, so there is no need to have a method with
Same thing. There are no material changes in the IDE path, if you look closely. I'll add a new comment below which explains the flow before and after. I'll also look at the test suite. However, I have the problem currently, that I can't build using build.ps1, because it tries to target .NET standard with C# constructions that are too new:
These refer to bracket-less namespace declarations, which are not valid for older C#. |
Existing flow when entering through a list of assemblies and filter, so, from dotnet test (not via the IDE). This list itself is repeating from an earlier comment.
The first issue comes in step 6, where we clear the filter based on how many tests it enumerates, even though this has no connection at all with the size of the filter. In fact, from dotnet test, most filters will be short, but can still enumerate many tests. The next issue is in step 8, where we insist on converting the filter to a list of tests, which will almost always make the filter much longer than it was. There is no reason I can see, why this is done in non-IDE mode. In IDE mode, it will already be a list at this point, making it also superfluous. Note that if we are randomly lucky enough to have a category in the filter, we are saved from this conversion by step 7, which simply returns out of the method early (for no reason I can tell). So, my proposed PR removes the conversion to list and the clearing of filters than enumerate too many tests. That's it for non-IDE mode. I'll add another comment for how IDE mode is affected (which it almost isn't). |
The IDE-mode run is much simpler:
Here step 1 is the same as non-IDE mode, and step 2 here is the same as step 3 above, and step 3 here is a variant of step 6 above (the CheckFilter method is shared). My PR proposal will simply remove step 3, since it does nothing we didn't already do. |
NUnit 3.12.0
NUnit3TestAdapter 4.5.0
.NET 6.0 (Windows command line with dotnet test)
It has already been discussed in the past (#998 and others) that exceeding 2000 test cases with FullyQualifiedName filter will cause the execution of all tests regardless of the filter. As I understand this is supposed to address issues when running tests from Visual Studio when the test filter gets too huge like described in #660, but why is that limitation also applied when running tests from console with just a single FullyQualifiedName filter?
Couldn't this be applied only when running tests from Visual Studio?
The Execution.CheckFilter() method already supports returning a raw filter when TestCategory filter is included. In that case AssemblySelectLimit doesn't matter and individual test cases from filterBuilder.FilterByList() are not returned. Why isn't this behaviour used when amount of loaded test cases (without TestCategory filter) exceeds the limit and we are not executing from Visual Studio? The calling code already verifies if it's an IDE execution or not and behaves differently.
Today we have a workaround of adding TestCategory filter with a fictive category to achieve such behavior (passing raw filter). Alternative with increasing AssemblySelectLimit probably should be avoided since this will create a very large test filter, with thousands of entries instead of our short filter for one category.
P.S. Please also note that even though all tests are executed, the result from dotnet test shows the filtered tests only, not all test cases (same problem as point 3 in #998). This is very misleading when trying to identify the problem.
The text was updated successfully, but these errors were encountered: