Currently the Simple Tests which come with apache solr require a working instance of apache solr to work. Instead, the low level interface to the apache solr service should be removed during the test and replaced with a mock object. We could then check that the apache solr code is sending the expected messages to apache solr in response to setup test conditions without actually sending to apache solr and checking the results.
As far as I am aware, there isn't currently an ability to do this with SimpleTest. This thread looks at how this might be achieved for the apachesolr project.
Note: this issue started life as a bug in beta16. Details below ...
The function apachesolr_entity_update is supposed to remove nodes from the index if their status changes to 0 (unpublished) however, as far as I can tell this is not happening.
I think this is because the code is_callable($status_callback) is returning false and this is because the status callback function for nodes is in the file apachesolr.index and this file is not included in this function.
| Comment | File | Size | Author |
|---|---|---|---|
| #37 | 1442358-37.patch | 565 bytes | nick_vh |
| #38 | 1442358-38.patch | 5 KB | nick_vh |
| #34 | apachesolr-tests_for_entity_events-1442358-34.patch | 13.1 KB | johnennew |
| #30 | apachesolr-tests_for_entity_events-1442358-30.patch | 11.66 KB | johnennew |
| #28 | apachesolr-tests_for_entity_events-1442358-28.patch | 12.12 KB | johnennew |
Comments
Comment #1
ndevelder commentedI can second that this is happening...I'm using rules to unpublish nodes, and they stay in the search index. I also call entity_save after changing the node title in a custom module, and the update does not propagate to the search index. I have yet to explore the module, but will report back if I come up with anything good...
Comment #2
ndevelder commentedSo after some digging, I've figured out that it is getting past the "is_callable($status_callback)", and properly assigning status to 0 and inserting the record into the table "apachesolr_index_entities_node" with a status equal to 0. But what happens from then on? It seems like there are a bunch of nodes here with status = 0 but that nothing calls the table to remove the records from the index?
Comment #3
ndevelder commentedI think I fixed this (at least temporarily for my purposes) by adding a check for $status = 1, and sending the entity to be deleted from the index if not...
Nodes leave the index as they should, and then when re-published, they come back....
Is this the best way to do this?
Comment #4
johnennew commentedThis patch fixes this in a different way, I don't know if it's any better though!
The function that is called by apachesolr_entity_update to decide the current status of a changed node is apachesolr_index_node_status_callback. This returns the new status of the node, so if just unpublished this will be 0. This status is then written to the apachesolr_index_entities_node table against the nid.
On cron, the function that finds unpublished nodes to be removed from the index is apachesolr_index_node_check_table and it makes the decision based on which nodes have a status which differs from the entry in the apachesolr_index_entities_node table. However, at this point the status will always be the same, so unpublished nodes will never be detected.
My patch changes the output of apachesolr_index_node_status_callback to return the oposite of the current status so it can be picked up. I do not know what other things this may change but it fixes my problem.
Comment #5
nick_vhOn it right now, looks critical
Comment #6
johnennew commentedThat patch has an error in it! Here is the correct one.
Comment #7
nick_vhCould you put the module_load_include at the top of the function?
Comment #8
nick_vhComment #9
nick_vhCommitted! Thanks!
Comment #10
johnennew commentedI don't believe this works as apachesolr_index_node_status_callback is setting the status in the apachesolr_index_entities_node table to the current state of the node. When the index is updated via cron the function apachesolr_index_node_check_table runs the following code to find nodes to unpublish:
This finds all nodes whose status differs from that in apachesolr_index_entities_node but the patch #8 will leave it the same and so this code will never see unpublished nodes.
The following patch is an update of #8 but changes it to the opposite. This feels wrong but it does seem to be working.
Comment #12
nick_vhOk, Before we continue I'd like to get some simpletests first so we can actually figure out if everything works as expected. Care to do that?
Comment #13
jody lynnI think that what was committed is right and disagree with #10.
My impression is that apachesolr_index_node_check_table is only there to catch problems that slip through. Right now I have a lot of nodes that it's trying to fix because they are never properly updated during node_save (which the patch in #8 fixes). Nodes that are properly matching between the two tables will already be indexed and don't need to be caught by this check function.
I just updated to dev and will reindex with the patch in #8. I have a big site with a lot of activity so should be able to tell pretty quickly if this still needs work.
Comment #14
Georgique commentedSubscribe
Comment #15
nick_vhJody Lynn, possible to get back to us with an update?
Comment #16
johnennew commentedI cannot find the code that actually removes a node from the index.
From #13 above, I think you are correct in what you say about the apachesolr_index_node_check_table only there to catch problems, but how does the node get removed from the index before this table is updated by a call to apachesolr_entity_update? I can force the problem by setting it wrong as per my patch in #10 but this is certainly the wrong way to do it. A clear of your index should be rebuilt properly but then apachesolr_entity_update won't get called in a rebuild (I think!).
Nick_vh, you asked for a simpletest for this but I am not an expert and struggled with this I am afraid. The problem, I think, is that I do not know what the expected behaviour is. What happens when a node is unpublished? Should a node be scheduled for removal from the index (in which case how does this happen, messing up the apachesolr_index_node_check_table as in #10 is clearly wrong) or should it be removed immediately, which is what ndevelder has suggested in #3?
Comment #17
nick_vhIt should be removed using apachesolr_index_delete_entity_from_index
So, for a test :
- Add a node and make sure it is published
- verify if this node exists in our indexer_table with status 1
- Run indexing (cron or the function)
- Check if the node was submitted
- Unpublish the node
- verify if this node exists in our indexer_table with status 0 and a new changed timestamp
- verify if the node was removed from solr
The only bad thing that happens in the module is that deleted nodes are not scheduled for deletion but are deleted immediately. We could improve this but this would be another issue
Afaik, no such thing is happening. apachesolr_index_get_entities_to_index only indexes entities with status 1 so we should probably add an extra if check in entity_update and when the status from the function call returns 0 it should remove the entity from the index using apachesolr_index_delete_entity_from_index.
This way we have an easy way to control if unpublished nodes should be indexed or not. One could easily return TRUE for the status callback so it indexes unpublished nodes.
Understood?
Comment #18
johnennew commentedHere is a patch which includes ndevelder fix from #3 - I will look at creating a test in accompany this.
I have been using this fix on my testing systems and it appears to be working. When a node is unpublished it is immediately requested to be removed from the index.
Comment #19
nick_vhSeems to be good yes. This matches the use case I explained above I think
Comment #20
nick_vhBefore we can mark this as reviewed and ready I'd love to have some simpletests. Please chip in if you have time :-)
Comment #21
nick_vhComment #22
jody lynnThe dev (what was committed in #8) fixed my problem.
My problem was that nodes that started out as unpublished and then were edited and set to published were never added to the index. They would be attempted to be fixed on apachesolr_index_node_check_table but that would also fail to index them for some reason and so it would try the same list of nodes each cron run.
A test would be to create a node that's unpublished and a node that's published. Index and make sure only the published node appears in search. Then edit each one and reverse their statuses and index. The reverse should appear in search.
Sound about right for the tests description?
Comment #23
nick_vhSounds about right, now we just need someone to do it ;-)
Comment #24
johnennew commentedHi, here is a first example of some tests which do as specified above. I'm fairly new to Drupal SimpleTest framework so would appreciate some constructive feedback on this.
I've not been able to find how you would go about Mocking the behaviour of the Solr service, the DummySolr class doesn't appear to do enough yet. I have put in place a suggested Mock object which is a drop in replacement for the DrupalApacheSolrService class (or indeed any object) for the purposes of unit testing so that the functions the module tries to run can be checked without actually needing an ApacheSolr service running for the tests to work.
Kind regards,
John
Comment #25
johnennew commentedSorry that last patch only had the new test file in it, this one includes the changes to some other files as well.
Comment #26
nick_vhLet's give the testbot some crunching :-)
I'll check in detail later, thanks!
Comment #28
johnennew commentedI might not have had the latest version of the code, did a git pull origin 7.x-1.x and recreated the patch. See if this works...
Comment #30
johnennew commentedOK, not sure if I understand the error so completely rechecked out the code, reapplied my changes and recreated the patch. If this doesn't work some one will have to explain it to me!
Comment #32
johnennew commentedSwitched to development branch and queued for retesting
Comment #33
johnennew commented#30: apachesolr-tests_for_entity_events-1442358-30.patch queued for re-testing.
Comment #34
johnennew commentedA better Mock object. Let me know If this approach is OK.
Comment #35
nick_vhWow, I was absent for a little while. What a great attribution!
However, I should look more closely to this patch because it adds a bunch of code (and since the testing bot is green it seems like it is good code)
Do you think your mock object is able to handle all testing interactions towards solr without having a real solr?
Comment #36
johnennew commentedHi Nick_vh,
Thanks for your comments. I've been developing this mock for integrating external systems with Drupal in a few client projects over the last year and seems to be working well. I think it would be a good replacement for the Dummy_Solr class certainly and I expect it would work in place of the rest of the test code, removing the need for an actual solr instance to run the tests.
After you've had a closer inspection I would be happy to rewrite the rest of the Solr tests to use this methodology if you think it would be of use. Also happy to sign up as a module maintainer if appropriate.
John
Comment #37
nick_vhjohnennew - I commited the included patch for the status into the project (6.x-3.x & 7.x-1.x)but I am going to wait with the mock object a bit till we get some more reviewers. I do like the dynamics it allows.
Comment #38
nick_vhThis patch includes only the mock object
@johnennew - If possible I'd like to see all the live tests (or as many as possible) converted to this mock object. Would you be able to do that? Currently it checks if we have a live solr available and if so, it runs an additional set of tests. This makes the test different on a local platform compared to drupal.org. Preferably we want to get rid of this difference
Comment #39
johnennew commentedNick_vh - yep, I'd be happy to get involved. I'll look at doing some of this work over the next week. Should we move this to a new issue?
John
Comment #40
nick_vhI already renamed it, no worries - I prefer to keep the history where this came from. You can however change the issue summary already to reflect in more detail what is expected. Also look in the issue queue, there should be an ancient issue that tried to do the same.
Comment #41
kriboogh commentedAny news on the status of this mock object for testing? We are running a multisite setup, I got the sandbox version working of apachesolr_multisite in D7. I would like to extend the module with some simple tests. Do you think I could subclass this mockup object to allow it to return multisite test data?
Comment #42
nick_vhkriboogh, be my guest to do that. We are still in the progress for converting most of the test suite to this mock object. This can take a considerable amount of time so any contribution is welcome
Comment #43
nick_vhGoing to categorize this as a feature request. It is certainly not a bug nor a blocker
Comment #44
nick_vhpostponing for now - let's get the module stable and get away from scope creep
Comment #44.0
nick_vhThe purpose of this issue changed as the conversation progressed. Updated the top level description so it still makes sense.