When you run Behat tests that upload files, the files are not deleted after the scenario is finished. This is in contrast to nodes and users, which are deleted.

This is complicated by the fact that you've got the original uploaded file, any image styles generated during the test, and the file entity. If the filename matches one that's already present, it will have _N appended, so you can't necessarily just delete the file matching the name you uploaded.

There may be some way to get at a file_entity function and use that to delete the correct version and all the styles.

Comments

dsnopek’s picture

The way the nodes get deleted is by deleting all the content that the user (which was created by Behat) created. We could figure out which files to delete the same way - there is a 'uid' column on the 'file_managed' table.

As far as the image styles, it looks like the 'image' module cleans those up when a file is deleted via file_delete() in it's hook_file_delete(). So, it looks like we should be able to just loop over the files, calling file_delete()!

cboyden’s picture

Title: FIle upload tests do not clean up after themselves » File upload tests do not clean up after themselves
Status: Active » Needs review
StatusFileSize
new5.48 KB

OK, here's a proof-of-concept patch that adds these things:

  • A step "Given the managed file [filename]"
  • A managed_file.feature that verifies that the managed file can be seen at admin/content/file
  • An AfterScenario hook that deletes files created during the scenario, INCLUDING files uploaded via the UI during widget tests

The code that creates the file is working fine. The deletion code has a problem, which I've worked around in the AfterScenario function.

For some reason, file_delete cannot find the actual file when run from this function. It keeps reporting "The file public://test.txt was not deleted, because it does not exist." If you go to the UI and delete a file uploaded by the Given step, it works OK, deletes both the entity and the file successfully. But in the AfterScenario function, the actual file does not get deleted.

I've checked local permissions (all directories in the tree are world-executable). I've checked that some other functions that use $file->uri work. For example, you can call the PHP function file_get_mimetype on $file->uri and get the right result. But for some reason, PHP and Drupal can't find the file using the URI. So I've added a hacky step to determine the real path of the file by parsing the URI, and unlink it if it still exists after file_delete. Ideally this should be fixed and the hack removed.

dsnopek’s picture

StatusFileSize
new4.34 KB

The reason for the weirdness is that the stream wrappers are using relative paths from DRUPAL_ROOT, so, you need have the current working directory be DRUPAL_ROOT for the file functions to work correctly.

I've created a new version of the patch that chdir(DRUPAL_ROOT)s before running any file functions, and then returns to the previous current working directory.

I also made a bunch of coding-style fixes - sorry, I couldn't help myself. :-)

In any case, it works for me in both (a) creating and cleaning up files created with the new step, and (b) cleaning up files created by test users in other tests!

I'll commit shortly.

  • dsnopek committed ccbaa59 on 7.x-1.x
    Update Panopoly Test for Issue #2268647 by cboyden, dsnopek: File upload...
dsnopek’s picture

Status: Needs review » Needs work

Er, unfortunately, Travis-CI came back with an error. :-/

https://travis-ci.org/panopoly/panopoly/jobs/47988858#L970

Need to figure that out!

cboyden’s picture

I think what's happening is that the managed file uploaded by the contentpage.feature is being deleted twice. The new AfterScenario hook in this patch deletes all managed files affiliated with the current test user regardless of whether they're in use or not. It's set up this way because Fieldable Panels Panes aren't deleted, so any files uploaded with the file or image widget will report themselves as in use.

Then when the AfterScenario hook included in DrupalContext runs, it deletes the content page with the featured image. The featured image field refers to a file that no longer exists, so you get this error.

If we could programmatically delete FPPs in our new AfterScenario hook before the file delete function runs, we wouldn't need to force deletion. See #2402845: Fieldable panel pane data not cleaned up after scenarios.

dsnopek’s picture

Actually, contentpage.feature isn't using FPP, it's attaching the file to a node - but it could be the same thing: the node is causing the file to be deleted before our function gets to it. The weird thing is that that test works for me locally - it's actually what I was using to test the file clean-up functionality! Anyway, we'll get to the bottom of it. :-)

cboyden’s picture

Our new function gets to the file first. It deletes anything created by the current user regardless of usage. If the included cleanup function got there first, there wouldn't be a problem - the file wasn't created by our custom Given step, so it wasn't added to the $files array, and it wouldn't still be there in the DB to be collected by the generic cleanup function.

If we had an FPP cleanup function, we wouldn't need the generic cleanup function to delete regardless of usage. We could delete the FPPs first and then the files wouldn't be used anywhere.

Maybe generic file cleanup could go into an AfterSuite function?

cboyden’s picture

Generic file cleanup unfortunately can't go into an AfterSuite function, because those run outside of the scenario context and so don't have access to any of the functions or variables we'll need.

I have an approach that's working locally to delete fieldable panel panes whose first revision was created by a current test user. That's one angle, which allows me to remove the TRUE parameter from file_delete. What that leaves behind is files uploaded to the WYSIWYG using the Media button. Hooks run in the opposite order from the order they're registered, so it looks like our added hooks will always run before the hooks included in DrupalContext. So images inserted into WYSIWYG fields in test pages will always have usage records that prevent their deletion when our cleanup function runs.

I'm working on an angle to call file_usage_delete on images referenced by entities owned by the current test user, which will allow the cleanup function to do its magic on them.

cboyden’s picture

This is complicated.

cboyden’s picture

Here's a patch that deletes Fieldable Panels Panes and removes the TRUE parameter from file_delete. It is working locally to clean up files uploaded via the Image and File widgets. It still leaves behind images/videos (and I assume other file types) inserted into WYSIWYG fields on pages created by test users.

Since the patch in #3 was committed, this patch applies on top of it instead of replacing it.

cboyden’s picture

Status: Needs work » Needs review
cboyden’s picture

StatusFileSize
new4.14 KB

Here's a patch which adds cleaning up files that are created by a test user and inserted using the Media button. Seems to work for images and videos, at least!

cboyden’s picture

The AfterScenario hook fails on the one-time login test - maybe the Given step doesn't add the user to the $users variable?

  • dsnopek committed 2ad13ec on 7.x-1.x
    Revert "Update Panopoly Test for Issue #2268647 by cboyden, dsnopek:...
dsnopek’s picture

StatusFileSize
new6.5 KB

So, first of all, I've reverted the last commit! Here's a patch merging the latest patch with the original patch so we have something to we can commit after the revert.

Some quick nit picky patch review (against the patch from #13):

  1. +++ b/tests/features/bootstrap/PanopolyContext.php
    @@ -24,11 +24,12 @@ class PanopolyContext extends DrupalContext
       /**
    -   * Keep track of files added by tests so they can be cleaned up.
    +   * Keep track of files and FPPs added by tests so they can be cleaned up.
        *
        * @var array
        */
       public $files = array();
    +  public $fpps = array();
    

    This should be two seperate documentation blocks for each property.

  2. +++ b/tests/features/bootstrap/PanopolyContext.php
    @@ -193,13 +233,29 @@ class PanopolyContext extends DrupalContext
    +    //figure out if there's usage in any nodes;
    

    Inline comments should follow normal Drupal coding standards, ie. have a space between // and then text, start with a capital letter and end with normal sentance punctuation.

I'm going to try this on Travis-CI in a moment to get an idea of where we are on what's passing or not:

https://travis-ci.org/dsnopek/panopoly/builds/48489134

EDIT: That was the wrong patch. :-/ Here's a new Travis URL with the right patch:

https://travis-ci.org/dsnopek/panopoly/builds/48500083

cboyden’s picture

Status: Needs review » Needs work

The one-time login link test failed. Adding the @api tag to the AfterScenario hook that cleans up files should fix it. I'll take a look at that and also the coding standards things you mentioned.

cboyden’s picture

Status: Needs work » Needs review
StatusFileSize
new6.72 KB

Here's an updated patch. Adding the @api tag to the new AfterScenario hook prevents the one-time login test from failing. (If files or FPPs are added in tests that don't require the API, then they won't be cleaned up. Right now there are no black-box tests that do that.)

I also did some code cleanup on comments and doc blocks.

Local results indicate this patch is successfully cleaning up FPPs added by tests and files/images added by tests.

dsnopek’s picture

Patch looks good from a code review perspective! I'm going to run it through Travis-CI quick and if it passes, I'll commit:

https://travis-ci.org/dsnopek/panopoly/builds/48527336

dsnopek’s picture

Status: Needs review » Fixed

Passed on Travis-CI! Commited.

  • dsnopek committed a63f2a5 on 7.x-1.x
    Update Panopoly Test for Issue #2268647 by cboyden, dsnopek: File upload...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.