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

Various Test Improvements #8

Merged
merged 2 commits into from Jun 29, 2022
Merged

Various Test Improvements #8

merged 2 commits into from Jun 29, 2022

Conversation

zombiepigdragon
Copy link
Contributor

Type of pull request

This PR makes changes to the test structure and introduces a basic fuzz test harness, as well as fixing a few panics that were tripped while writing the tests.

Overview of pull request

This PR follows through on the majority of #5 (comment). In particular, it moves the integration tests to become unit tests, completely removes the TestServer struct, adds a fuzz harness to detect panics that can be reached from outside, changes the hardcoded buffer sizes to be dynamically sized, and makes a few changes from what I assume to be the correct non-panicking behavior. In particular, I embedded the default media/ error pages into the binary, rather than simply panicking when they are not present- they are still possible to override (though there isn't a test case for that yet.) I decided to remove one of the existing test cases, because I don't think there's anything to do server-side for CORS checks, and I believe it would be easier to remove it than to reimplement the checks (another case where a future test would be good.) The base unit tests now cover roughly 65% of the codebase by the same metric as earlier, almost doubling previous coverage. As far as fuzzing, I ran it for roughly an hour with no crashes, and am currently reasonably confident that it is difficult for external requests to cause a panic at this point.
I'm leaving this as separate commits right now to simplify reviewing it in parts, but would be happy to squash the changes into a single commit or multiple smaller commits if desired.

Future possibilities

I did not end up writing any integration tests for this PR. After making the changes I did, I think that going forward, the best course of action would be to move most of the server's unit tests back to being integration tests, but using a third party HTTP client over a socket rather than attempting to create a request by hand. The tests that remain as unit tests should be the ones that e.g. test an empty body and providing broken unicode. I've spent long enough not submitting this PR that I decided to leave it as is, but there are also some additional tests that would be good to write:

  • Check for specific headers (i.e. CORS)
  • Check that only the configured verbs are accepted
  • With a multithreaded server, send two requests, then read them in reverse order (the first shouldn't prevent the second from finishing)
    If desired, I can redo the hack in the server unit tests to use once_cell, or even just replace it with a static junk path (I don't think it's ever used, so it would be fine to hardcode it to "nonexistent").

This change also separates the different tests, rather than leaving them
as a one test function that checks multiple conditions.
@PeterPierinakos PeterPierinakos self-requested a review June 28, 2022 20:21
Copy link
Owner

@PeterPierinakos PeterPierinakos left a comment

Choose a reason for hiding this comment

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

Seems like most of the changes you have done are really well integrated and you have fixed some bugs with the current codebase. I will do some personal testing with the changes of this PR on my local machine before merging with the main branch since this PR seems to be quite large.

@PeterPierinakos
Copy link
Owner

I've been testing the changes and I have found some problems. Here are some of the most notable ones:

  1. (This first one is your highest priority.) The server doesn't respond to any of my requests when I run it from your fork and I try to send a request to the server using curl http://localhost:80. Doesn't matter if I run as root or not. This seems to be caused by read_stream and some of the changes you made to it.
  2. At line 21 of file.rs, you try to access the media files which shouldn't be accessed by the program. You can imagine the media files as "stage 1" of implementing the static files because after you put them there you are supposed to run ./setup.sh which will copy all of them to /var/www/static/ (the default static path), so you are supposed to access them via that. The changes made to media/ should be local.
  3. Some of the changes you have done are redundant. For instance, changing the match statement to an if ... else ... statement inside response.rs is unnecessary, so you should probably revert that change.
  4. read_error_file hard checks for if the filename is any of the 4 error pages. The logic is already handled by the beginning of create_file_response, so I believe that this change is also redundant and should be reverted to the function's original state.

I'm willing to squash the commits as one once you fix and address the following issues and do some of the changes I suggested. I'm fine with some of the other minor issues such as the Box::leak in the fuzz_serve_request, but the ones I mentioned above should be fixed before merging.

@PeterPierinakos PeterPierinakos linked an issue Jun 29, 2022 that may be closed by this pull request
@zombiepigdragon
Copy link
Contributor Author

(This first one is your highest priority.) The server doesn't respond to any of my requests when I run it from your fork and I try to send a request to the server using curl http://localhost:80. Doesn't matter if I run as root or not. This seems to be caused by read_stream and some of the changes you made to it.

Yep, I realized this would happen after I slept- I replaced read with read_to_end, which works fine in tests and avoids possible truncation, but isn't actually correct because HTTP doesn't close the stream until the reply is sent- I'll update that once I'm done typing here.

At line 21 of file.rs, you try to access the media files which shouldn't be accessed by the program. You can imagine the media files as "stage 1" of implementing the static files because after you put them there you are supposed to run ./setup.sh which will copy all of them to /var/www/static/ (the default static path), so you are supposed to access them via that. The changes made to media/ should be local.

The reason I did this was that the program was originally crashing when they were missing, which I ran into during testing (since my workstation isn't a server, I reconfigured it to a local directory and thought that would be sufficient.) I believed the most useful behavior was to have an easily-available version of the files. IMO, even with misconfiguration, the server should never panic, especially as a result of a runtime condition. I'll revert that for now, but consider fixing that in the future.

Some of the changes you have done are redundant. For instance, changing the match statement to an if ... else ... statement inside response.rs is unnecessary, so you should probably revert that change.

It does have a purpose- it makes it possible to move responsibility for reading the error files into the other function, which allows not returning a file. It'll be reverted as well.

read_error_file hard checks for if the filename is any of the 4 error pages. The logic is already handled by the beginning of create_file_response, so I believe that this change is also redundant and should be reverted to the function's original state.

See above.

@PeterPierinakos
Copy link
Owner

The reason I did this was that the program was originally crashing when they were missing, which I ran into during testing

Yeah, this is intentional because I wanted to have a directory which would kind of work as a "development environment" so that you can test your changes and not have them apply when you rerun the server. This may be improved in the future, but it currently works.

Just inform me when you commit the read_to_end bug fix and I'll merge to main 👍

This commit (PR #8) modifies the testing framework and introduces a
fuzzer to the codebase. Pre-squash commit messages can be found below.

Replace fixed size buffer with a Vec<u8>

This allows for using files of over 1024 bytes when needed. However,
this commit still defaults to allocating a 1024 byte buffer for each
request, and so does not likely reduce memory usage.

Avoid panicking when error files don't exist

Instead of panicking, the default files included in /media will be
served. To accomplish this, these files are embedded into the binary at
compile time. It is still possible to overwrite them by creating the
expected files.

Remove TestServer

In its place, this commit modifies Server and some additional functions
to be generic over their reader and writer, allowing unit tests to use
the standard Server serve_request function. In addition, some bug fixes
were made to allow the new tests to actually pass.

Introduce fuzzing framework

Fix bug found by fuzzing

Revert "Avoid panicking when error files don't exist"

This reverts commit 5c4e2f5.

Copy media files to test directory

Fix server hanging in real tests
@PeterPierinakos
Copy link
Owner

By the way, I will fix the runtime panics in a future commit of mine (#9)

@zombiepigdragon
Copy link
Contributor Author

zombiepigdragon commented Jun 29, 2022

@PeterPierinakos I've squashed and pushed. It should work now, sorry about breaking it the first time!

Edit: Oops, tests failed because I forgot about a bug- the code to load 400.html and its counterparts relies on configuration.rs, so it doesn't work in combination with the tests. I'm not sure about the cleanest fix, since it would be a pretty big change to just pass the configured path all the way down the call chain. Thoughts?

@PeterPierinakos
Copy link
Owner

Could you specify on what file and line the bug occurs in more detail so that I can take a look myself? By the way, I ran the tests on my local machine with your new changes and they worked just fine so I'm not sure why CI failed.

@zombiepigdragon
Copy link
Contributor Author

In /src/util/file.rs line 16, the current configured ABSOLUTE_STATIC_CONTENT_PATH is used. If there are files in that directory, the tests will pass, but without setting up /var/www/static the aforementioned panic due to missing files will trip. CI doesn't use that directory, so the tests fail when it can't find the files.

@PeterPierinakos
Copy link
Owner

Oh, I thought you were talking about the tests breaking locally and not with CI, that's where my confusion came from. Could we possibly configure GitHub Actions to run the setup.sh bash script before executing the tests since I'm guessing it's running on top of a Linux distribution? Or do we have to implement your suggestion and entirely remove /var/www/static and just use the media/ directory which isn't outside of the repository as previously mentioned? The laziest but also the easiest way to deal with this would be the latter I recommended.

P.S. During writing this I just thought that we could write special tests specifically for CI that would use the media/ directory and wouldn't be used by normal end users.

@zombiepigdragon
Copy link
Contributor Author

P.S. During writing this I just thought that we could write special tests specifically for CI that would use the media/ directory and wouldn't be used by normal end users.

This is the closest to what I expected. If you look in src/structs/server.rs line 276, I was hoping it would use tests/static and therefore avoid crashing. The problem here is that user configuration affects tests, which is usually not a good thing. /var/www/static or similar definitely should continue to be the default path, it would be really weird to default to having to install the site within the source code. Running setup.sh before launching tests is a working band-aid if you think that is the best way to go, but it doesn't always help. On my machine, the local tests failed after I reset configuration.rs (I had it set to the test files directory and a rootless port for debugging ease).

In short, I think the problem is that the configuration leaks into the find_file function, and it should somehow avoid being directly dependent upon the installed settings.

@PeterPierinakos
Copy link
Owner

I think 54378b7 should temporarily the CI issue. Because the configuration is a whole different topic and not very related to why this PR was initially created, I am now closing this issue as we have finally managed to integrate tests into the codebase. If any issue with this change persists after merging, feel free to create a new issue. Going to approve and merge now.

Copy link
Owner

@PeterPierinakos PeterPierinakos left a comment

Choose a reason for hiding this comment

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

All things that were needed to be fixed were fixed. Thanks for the effort put into addressing the issue and the PR!

@PeterPierinakos PeterPierinakos merged commit 7027760 into PeterPierinakos:main Jun 29, 2022
PeterPierinakos pushed a commit that referenced this pull request Oct 8, 2022
This commit (PR #8) modifies the testing framework and introduces a
fuzzer to the codebase. Pre-squash commit messages can be found below.

Replace fixed size buffer with a Vec<u8>

This allows for using files of over 1024 bytes when needed. However,
this commit still defaults to allocating a 1024 byte buffer for each
request, and so does not likely reduce memory usage.

Avoid panicking when error files don't exist

Instead of panicking, the default files included in /media will be
served. To accomplish this, these files are embedded into the binary at
compile time. It is still possible to overwrite them by creating the
expected files.

Remove TestServer

In its place, this commit modifies Server and some additional functions
to be generic over their reader and writer, allowing unit tests to use
the standard Server serve_request function. In addition, some bug fixes
were made to allow the new tests to actually pass.

Introduce fuzzing framework

Fix bug found by fuzzing

Revert "Avoid panicking when error files don't exist"

This reverts commit 5c4e2f5.

Copy media files to test directory

Fix server hanging in real tests
PeterPierinakos added a commit that referenced this pull request Oct 8, 2022
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.

There should be a test suite for this program
2 participants