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

Unstable test "should reload config on change" #1700

Closed
raman-m opened this issue Sep 23, 2023 · 15 comments · Fixed by #1703 or #1705
Closed

Unstable test "should reload config on change" #1700

raman-m opened this issue Sep 23, 2023 · 15 comments · Fixed by #1703 or #1705
Assignees
Labels
bug Identified as a potential bug merged Issue has been merged to dev and is waiting for the next release

Comments

@raman-m
Copy link
Member

raman-m commented Sep 23, 2023

Expected Behavior

The test should_reload_config_on_change doesn't fail in 100% of running

Actual Behavior / Motivation for New Feature

Currently the test should_reload_config_on_change fails sometimes: in 1/3 or even 1/2 cases.
Possible reason: multithreading for file access when test class tests being run in parallel.

Steps to Reproduce the Problem

develop builds:

PR builds:

Specifications

  • Version: latest
  • Platform: Docker
  • Subsystem: CircleCI
@raman-m raman-m added the bug Identified as a potential bug label Sep 23, 2023
@raman-m
Copy link
Member Author

raman-m commented Sep 23, 2023

@ggnaegi Hey Guillaume!
Could you look into this problem, please?

@raman-m raman-m added the accepted Bug or feature would be accepted as a PR or is being worked on label Sep 23, 2023
@raman-m raman-m changed the title Unstable test 'should reload config on change' Unstable test "should reload config on change" Sep 23, 2023
@ggnaegi
Copy link
Member

ggnaegi commented Sep 24, 2023

@raman-m Ok, we have a problem here. How could I possibly reproduce the same conditions as the CI Pipeline?

In xUnit, tests (facts) are designed to be run in isolation, which means there's no guaranteed order of execution. This is intentional and follows the unit testing best practice of ensuring that each test is independent and doesn't rely on state changes from other tests.

@ggnaegi
Copy link
Member

ggnaegi commented Sep 24, 2023

@raman-m What we could do, is provide a factory for the configuration files and change the configuration files id depending on the facts

@raman-m
Copy link
Member Author

raman-m commented Sep 24, 2023

@ggnaegi
I see 2-3 possible solutions:

  1. Make test class tests running sequentially via good known xUnit attribute. Most easy and fast fix delivery. But it seems you don't like this solution.

  2. If you want to make each test totally independent then we have to abstract from hardcoded ocelot.json file, and apply test id prefix/suffix in the file name to make tests independent.

  3. On the level of all acceptance tests create multithreading synchronization primitive for access to ocelot.json file, and apply multithreading lock of the file for these tests.

1st solution is sequential.
2nd and 3rd are multithreaded/ parallel.

Complexity:
1st is the simplest.
2nd is a compromise, it is not complex but requires writing some code.
3rd is the most complex, it requires to change at least all tests which reads/writes from/to ocelot.json file.

I'm okay with all three solutions because they fix stability of the test.
But they require different efforts to implement, like time & coding.

Please, choose the favorite solution which you're liking...

@ggnaegi
Copy link
Member

ggnaegi commented Sep 24, 2023

@raman-m 1 is ok, but xunit assumes the facts in the same class are isolated and side effects free. So it would mean, we would have to refactor the code like that:

[Collection("Sequential")]
public class Sequential1
{
    [Fact]
    public void should_reload_config_on_change() { /* ... */ }
}

[Collection("Sequential")]
public class Sequential2
{
    [Fact]
    public void should_not_reload_config_on_change() { /* ... */ }
}

It's a bit ugly, no. So that is why I came up with the factory idea...

@raman-m
Copy link
Member Author

raman-m commented Sep 24, 2023

@ggnaegi
What are the side effects?

You can simply extract all tests that use ocelot.json to a separate class and disable parallelizm on them.
It seems you have to...

@ggnaegi
Copy link
Member

ggnaegi commented Sep 24, 2023

@raman-m Yeah well, it's sunday, it's mistakes prone...
Maybe we should only make sure the facts are using their own ocelot.json file? And then cleanup?

@raman-m
Copy link
Member Author

raman-m commented Sep 24, 2023

I like the 2nd solution to run test on a separate test file.
Did you count tests which use ocelot.json file?

@ggnaegi
Copy link
Member

ggnaegi commented Sep 24, 2023

I like the 2nd solution to run test on a separate test file. Did you count tests which use ocelot.json file?

@raman-m We have 168 references toGivenThereIsAConfiguration.... So I'm quite surprised that we haven't other tests failing...

@ggnaegi
Copy link
Member

ggnaegi commented Sep 24, 2023

In xUnit, each [Fact] or [Theory] method gets a fresh instance of the test class. This means that any instance variables you've declared in the class are re-instantiated for each test method.

So, the Steps class is re-instantiated for each test method. So each fact/theory has his own Steps instance. Maybe we could use a uuid in Steps class and create a path like uuid-ocelot.json

In Dispose, we would delete the uuid-ocelot.json file.

@raman-m I have the feeling, that would be a good solution...

@raman-m
Copy link
Member Author

raman-m commented Sep 25, 2023

@ggnaegi
branch bug-1700
The problem is not in parallel execution! I've applied a quick fix to disable parallelization, but it didn't help.
Probably all tests which use ocelot.json must be converted to sequential...
There will be no hotfix :(

@ggnaegi
Copy link
Member

ggnaegi commented Sep 25, 2023

@raman-m As you can see, I can reproduce the error with Open_circuit_should_not_effect_different_route(). After 133 iterations it eventually failed.
image
The good news is, in the last 20 tests I started, the error with reload didn't occur...

@raman-m
Copy link
Member Author

raman-m commented Sep 25, 2023

@ggnaegi commented on Sep 25:

As you can see, I can reproduce the error with Open_circuit_should_not_effect_different_route(). After 133 iterations it eventually failed.

How did you run so many iterations?
Let's create new issue and make new PR after delivery of this bug fix. But, it is not urgent!

@ggnaegi
Copy link
Member

ggnaegi commented Sep 25, 2023

@raman-m commented on Sep 25

-> Test Explorer -> Run Until Failure

@raman-m
Copy link
Member Author

raman-m commented Sep 25, 2023

@ggnaegi commented on Sep 25:

-> Test Explorer -> Run Until Failure

OK! 😃
And FYI, I've created #1706

raman-m added a commit that referenced this issue Sep 25, 2023
…g parallel execution (#1703)

* When instantiating steps, creating a custom ocelot config file name. Finally deleting the newly created config file when disposing the Step instance.

* Removing DeleteOcelotConfig from GivenThereIsAConfiguration, since File.WriteAllText will overwrite the file.

* using xunit.runner.json it's getting on my nerves

* Trying yet another strategy

* Revert "using xunit.runner.json it's getting on my nerves"

This reverts commit 9fac778.

* Not sure about GC.SuppressFinalize here

* correct usage of Wait.WaitFor...

* Do we really need to get a random port? Wouldn't be enough to get the next available port? Adding lock for thread safety

* Updating duration of break in Open_circuit_should_not_effect_different_routes from 1000 ms to 1500 ms

* ConfigurationReloadTests as sealed class

* moving variables initializations to Steps constructor

* putting back during of break to 1000, out of scope of current PR

* Code review

---------

Co-authored-by: raman-m <[email protected]>
@raman-m raman-m removed the accepted Bug or feature would be accepted as a PR or is being worked on label Sep 25, 2023
@raman-m raman-m added the merged Issue has been merged to dev and is waiting for the next release label Sep 25, 2023
@raman-m raman-m linked a pull request Sep 25, 2023 that will close this issue
raman-m added a commit that referenced this issue Sep 25, 2023
* Add sequential tests with disabled parallelization
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Identified as a potential bug merged Issue has been merged to dev and is waiting for the next release
Projects
None yet
2 participants