eShopOnContainers icon indicating copy to clipboard operation
eShopOnContainers copied to clipboard

Unit Test OrderingScenarios.Cancel_basket_and_check_order_status_cancelled causes NullReferenceException in EventBusRabbitMQ.Publish

Open InstanceFactory opened this issue 5 years ago • 4 comments

When debugging the unit test OrderingScenarios.Cancel_basket_and_check_order_status_cancelled, after having almost everything done, a NullReferenceExpcetion is thrown by EventBusRabbitMQ.Publish. This does not make the test case fail in the test explorer. One only notices it when debugging the unit test.
This exception is thrown when OrderingIntegrationEventService.PublishEventsThroughEventBusAsync tries to publish the cancel event, which was retrieved from the database table [Microsoft.eShopOnContainers.Services.OrderingDb].[dbo].[IntegrationEventLog].
Usually, Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services.IntegrationEventLogService.RetrieveEventLogsPendingToPublishAsync is going to deserialize the event data from the database into the appropriate type. To do so, the ctor of this class builds a list of IntegrationEvent types found in the entry assembly when it's called (Assembly.GetEntryAssembly()). Running / debugging the unit test, the entry assembly is testhost, …, and not the controller's API dll. Accordingly, the list of event types is empty and deserialization of the IntegrationEvent property fails, which leaves it as null.
The nullreference is passed by PublishEventsThroughEventBusAsync without verification to the event bus.
As I think that even while running / debugging unit tests no unexpected exception should be thrown, I suggest to add a check to OrderingIntegrationEventService.PublishEventsThroughEventBusAsync. In case the IntegrationEvent property of the current log event is null, it should try to deserialize it again. IntegrationEventLogEntry already provides the required method.
If you agree, I will create a PR.
To reproduce this behavior, all changes mentioned by #1407 have to be implemented.
Kind Regards,
Stefan

InstanceFactory avatar Aug 24 '20 16:08 InstanceFactory

Hi @InstanceFactory,

While I was testing eShopOnContainers, I noticed that whenever I run the application, make an order and then attempt to cancel the order, I get an exception. The app can't cancel an order. As I can see in the description of this issue, you're mentioning an issue in the unit tests and therefore proposing a solution to mitigate it. However, have you tried really cancelling an order via the MVC or SPA client? Did you get any error? If so, have you found any solution for that?

pedroasmsantos avatar Sep 13 '20 12:09 pedroasmsantos

Hi @InstanceFactory,

While I was testing eShopOnContainers, I noticed that whenever I run the application, make an order and then attempt to cancel the order, I get an exception. The app can't cancel an order. As I can see in the description of this issue, you're mentioning an issue in the unit tests and therefore proposing a solution to mitigate it. However, have you tried really cancelling an order via the MVC or SPA client? Did you get any error? If so, have you found any solution for that?

Hi @pedroasmsantos,

I've noticed the same behaviour when trying to cancel an order via the MVC app.

Finally I learned that the reason for the error I saw (in the app) is that while I tried to cancel the order, the status of it already changed in the backround to a state that does not allow cancelation any more. I think this is just reported to the user in a not so "user-friendly" way. The status change is done by processing some integration events by several services. While the order list is open in the UI, the state shown is not updated in case of a background status change.

So in the end it is a timing thing: In case you are fast enough (or the services are delayed for whatever reason), you should be able to cancel an order. I was able to do so, wihtout any code changes. One time my environment was quite slow (so the processing of the integration events did not happend before I canceled the order). Another thing I did was debugging the app and setting a breakpoint where the status of the order will be changed when an integration event is processed. Unfortunately, I do not recall where exactly that was.

The issue I am reporting here is only related to the unit tests, because things are not as expected (here, the executing assembly does not contain the required classes). It does not occur when you run the application.

Hope this helps.

Best Regards,

Stefan

InstanceFactory avatar Sep 14 '20 14:09 InstanceFactory

Hi there.. I was encountered this null exception too while integration tests on Ordering service specifically at PublishEventsThroughEventBusAsync method. The reason was similar as yours where _eventTypes return an empty collection after couldn`t find expected types. Below solution worked for me. Hope can help you.

        public IntegrationEventLogService(DbConnection connection)
        {
            //omitted for brevity

            _eventTypes =
#if DEBUG
                Assembly.Load(Assembly.GetCallingAssembly().FullName)
#else
                Assembly.Load(Assembly.GetEntryAssembly().FullName)
#endif
                .GetTypes()
                .Where(x => x.Name.EndsWith(nameof(IntegrationEvent)))
                .ToList();
        }

In this case, Assembly.GetCallingAssembly will return Ordering.API where the calling was originated.

hfz-r avatar Mar 11 '21 06:03 hfz-r

Hi,

I have the same issue. In my case Assembly.GetEntryAssembly().FullName equals ReSharperTestRunner.

@hfz-r solution is working for me.

Best Regards, Adrian

fruex avatar Sep 01 '21 14:09 fruex

I am closing this issue.

erjain avatar Aug 31 '22 07:08 erjain