AWS Bites Podcast

105. Integration Testing on AWS

In this episode, we discuss integration testing event-driven systems and explore AWS's new Integration Application Test Kit (IATK). We cover the challenges of testing events and common approaches like logging, end-to-end testing, and using temporary queues. We then introduce IATK, walk through how to use it for EventBridge testing, and share our experience trying out the X-Ray trace validation. We found IATK promising but still rough around the edges, though overall a useful addition to help test complex event flows.

AWS Bites is brought to you by fourTheorem, the ultimate AWS partner for modern applications on AWS. We can help you to be successful with AWS! Check us out at fourtheorem.com!

In this episode, we mentioned the following resources:

Let's talk!

Do you agree with our opinions? Do you have interesting AWS questions you'd like us to chat about? Leave a comment on YouTube or connect with us on:

00:02:31

And of course, if you're writing unit tests, you can mock some of that and simulate their behavior to make sure that part of your own business logic works well. But then at some point you need to make sure that also your own mocks are correct and your implementation actually works with the real backend, with the real AWS services. So that's when writing integration tests can help to increase the confidence that your application is actually going to perform well and be correct when you deploy to production. And it's very often that you will find bugs not in your code itself, but just the way that you are integrating things together. Maybe a configuration option is wrong, or maybe you assume that certain API will work in a certain way and then in reality works slightly different. So in your unit test, you didn't capture that behavior because you mocked that API and made assumptions. But then when you run it against the real service, then you realize that there was a mistake there or an edge case that you didn't include in your own logic. We usually like to mention as an example building e-commerce solution, because I think this is an example that everyone can relate to. And in that particular case, we can imagine that there is, I don't know, an order service and a delivery service. You might be writing them independently as two totally separate services. They might have their own tests, but then at some point they will have to be integrated together. So for instance, we might have the case where when you place an order, that order is pushed to something like EventBridge. And through EventBridge, there is a notification that gets picked up by the delivery service and the delivery service knows that an order was created and it starts to process it and do all the fulfillment procedure that you put in place for your own e-commerce. So that EventBridge is the tricky bit because how do you actually test it and how do you make sure that on one side you are producing the right type of event, on the other side you are picking it up and processing it correctly. So that's the question that we want to explore today.

Luciano
00:09:35

So what we tested is basically a very simple example and in this example what happens with this IATK tool is that it creates a temporary SQS queue and a temporary rule on the bus which uses the same patterns as the rule you want to test and that will allow you to basically put into SQS copies of the events that are happening so you can expect them and make sure that they look correct from an application perspective. It doesn't allow you to specify any pattern. You have to specify a rule and a target when you create a test listener and this seems a little bit strange. Now I don't know why it needs the target but we could be missing something that maybe is a little bit obvious to AWS and that we are not seeing here. Now the idea is that again you are trying to capture that event into SQS and then analyze it after you have been executing the code that you want to test. So it provides a number of helper functions for you to effectively clean up everything after you executed the test but also to inspect the state of the system after the test was executed. And you can also do things like clean up first just in case that a previous execution maybe left things in a little bit of a dirty state. So this is something that's actually recommended by the documentation and then you run your test, you do all of your own assertions and then in the third down phase you clean up again. Now before we go through all the features of this tool and how to use it, it's interesting to note that everything is available on GitHub including examples and what we did is basically we created an integration test for a repository that we call Cross Account Event Bridge which is something we built previously and it basically allows you to execute event bridge across accounts and share messages across accounts. And this is something we mentioned in a previous episode, episode 39, and you can find the link in the show notes if you want to know a little bit more about that specific use case and why we built it. Now this repository uses TypeScript for the CDK but because right now this tool only allows you to use Python, we wrote the integration tests in Python and we will also have a link to the specific test section in this repository if you want to find a quick way to go and just see how we brought the tests. So let's talk maybe a little bit about the process of creating this kind of test. Eoin, do you want to cover that?

Eoin
00:12:15

Yep, so what we did was we were using PyTest so you create your Python test then you use the AWS IATK Python module and instantiate it. Now immediately we kind of ran into an issue where it didn't pick up the credentials locally. The documentation says that it should pick up your AWS environment variables but I was just getting expired key all the time and I think it was picking them up from somewhere else like from a credentials file or config file. I don't use credentials for files so I don't know why but that didn't seem to work as documented so we had to actually specify a profile argument in the constructor in order to get this to work. Once we've done that then you just you need to know the event bus, the rule and the target. So IATK also provides some utility functions for reading cloud formation resource physical IDs or reading cloud formation outputs so that you can get those values for your stack. You mentioned also the cleanup process for ephemeral resources so you can use the IATK remove listeners helper to do that and you will it will use a tag filter to identify the resources that it can clean up safely. So you call that at the start of your test and then you also call it during your tear down. That's basically how you do it so that it clean up at the end of the tests normally but it'll also run at the start of tests in case there's anything dangling from previously aborted runs. So then you create an IATK listener so you give it the bus name, the rule name, the target ID and some tags and this will allow you to start checking for events. So when you create this listener under the hood it's creating an SQS queue and it's creating an event bridge rule to route events to that queue and it basically copies the pattern from the rule you provided. Again the fact that they ask you to provide the target ID as well doesn't make any sense to me because once you have a rule and a bus and you have a pattern that's all you need I think to do the test. So I didn't look into the code to find out what was that what that was all about. I'm not very good at reading Golang so I wasn't going to go in there and try to figure out what was going on but yeah maybe somebody can explain. I'm sure they have a valid reason for it. And then you have two options for actually retrieving the events and doing the validation. One is wait until event matched. This basically just waits for one event to come in on the bus and you provide an assertion function to check if the message is the one you expect. The other one is poll events. So this is a different model where you basically say you poll for events for 20 seconds and it'll give you all the events that arrive in that period and then you can go through them and filter them and check if they are valid yourself. In your tests teardown function then just remember to clean up the resources created by IATK. And you can see this example and we have in our cross-account event bridge e-commerce example we have the event bridge testing approach but we also tried out the trace validation with x-ray which seemed pretty exciting. We got some mixed results but we were able to get it to work. Luciano do you want to describe that process?

00:16:42

Now depending of course on the complexity of your code and how many systems are involved you might have to write lots of code to do these assertions correctly like it's not like a plain array where it's easy to assert certain things you might need to traverse the tree so it might be a little bit tricky to test exactly what you want to test but you have the entire view of all the systems involved there assuming that you enable and configure x-ray correctly. Now just to give you examples of the kind of matching that you might be doing on the trace tree for instance you might check if there are errors in any segment maybe a specific system was part of this transaction and that system produced an error maybe it's not something you might realize immediately by just looking at the final result of your execution but just looking at the tree you might realize that some of the components was failing in some unexpected way so I think it's good practice to try to traverse the tree and look for this kind of things and if you didn't expect any error in the case you see an error maybe make the test fail and report that particular error. You can also check performance metrics so make sure for instance if you have requirements in terms of SLAs regarding response times you might produce a warning or even fail the test if you see that certain numbers go beyond the thresholds that you expect as acceptable and you can also check if specific components were actually part of the trace maybe there are systems that don't really expose a behavior that you can assert at the end of your test but you just want to make sure that they received for instance some information and somehow they were part of this transaction so you can just assert that they were part of the trace tree at some point in the tree and finally you can also do the inverse for instance you might know that there are only three systems for example involved so you might assert that those three systems are there but if by any chance you see a fourth system that's probably a symptom that you are doing something a little bit unexpected so maybe something else that you might want to write an assertion about and make sure that only the things that you expect to happen are actually happening and nothing else is happening in the flow. So what are the things that we were happy with and the things that we were disappointed with?

Luciano
00:21:07

Yes mock event is something else we we tried and it's an interesting feature that you have available and the idea is that if you're using event bridge in event bridge you can have a schema registry so what this library allows you to do is basically to generate a mock event starting from your own schema registry and then use it effectively as a source for your own tests and for instance you you can say I want to generate a mock event that invokes a lambda or a step function and then that's basically the starting point of your own test and this can be convenient for instance when you have maybe a very complex flow and you want to break down the testing into individual parts maybe you want to test one integration at the time it can make it a little bit easier to actually have a clear starting point where you can craft exactly the event that gives you a good test case without having maybe to go through a bunch of additional steps that you might have in the entire flow so it's basically a way to make your test case start from an event in event bridge I don't think this was very applicable for our own testing so we kind of had more of a look at the documentation and so that looks like an interesting feature when you have kind of a multi-step approach maybe going through different rounds of generating events on event bridge picking up the event from there and doing something else but yeah in our case this wasn't really applicable but nonetheless it's an interesting feature that you might find useful and it's great to have the convenience to be able to create an event not let's say from scratch but starting with what you have already in your schema registry which should give you a little bit of confidence that the event is matching what you will actually have in a production scenario so what are all our overall thoughts like what did we like and what we didn't like about this new tool

Luciano
00:23:55

Luciano I can't bear it I can be the bearer of bad news so let's recap what we didn't like and just disclaimer this is probably due to the fact that this is a very new product it's still very early stage so everything we are saying here maybe it's not going to be applicable anymore in a few months as the product evolves and gets polished gets new feature gets bug fixes and so on so we already mentioned that traces didn't work the first time maybe our fault maybe we did something wrong but it wasn't really obvious how to do this just by looking at the documentation and copying their own example so definitely something to be improved either fixing bugs improving the documentation providing more examples and making this functionality easier to use correctly the other problem is that there is right now no SQS or SNS or Kinesis or Kafka support yet so really this is applicable today if you're using EventBridge but we know that EventBridge is not the only option here so depending on your architecture it might be disappointing to be able to test EventBridge but not to be able to test the other types of integrations documentation is there there is actually a website with a bunch of pages and examples but it looks like it was put together very quickly so it feels like there is a a lot more work to be done there for instance there is a section called tutorial and in that tutorial you only learn how to install the tool and then there is a link to some examples so I had the feeling that they want to create a more kind of fully fledged tutorial that walk you through all the different steps and gives you a bunch of different examples where every example is actually discussed what is the rationale behind the specific implementation for that example but right now you have to kind of fill the gaps on your own and just learn how to install it look at the code and the examples and figure out everything else in between now this is also a project that is open source so maybe if people are willing to contribute they can speed up the process of building this body of documentation and making the experience better for everyone else so that wouldn't be the first time for AWS to receive open source contribution and make specific tooling a little bit better so probably something where actually we have a chance to contribute and makes the project a little bit better the last one is on the RPC approach that we mentioned we like on one side because it makes this project more likely to be fully supported across languages in a consistent way even though today is all available for python the problem that we expect to see there is that with this kind of abstractions often when you have an error that error can be very obscure because it's just showing you for instance an issue at the python wrapper level but that error that you might see might be very generic and then the actual error is hidden in the go implementation which is abstracted away by the RPC wrapper this is something that we have seen for many many times i guess when when we use cdk and we see the kind of js ai errors appearing and it's always very hard to troubleshoot here because the design seems very similar we expect to have the same problem and this is maybe something that can be fixed by putting lots of attention in making sure that the rpc layer also propagates good errors and these errors are actually displayed well by all the different wrappers but nonetheless is an effort that ws needs to put into building the library and building the reporting tools when an exception happens so we expect this to be a bit of a friction point for people using the tool now again it's worth remarking that this project is in public preview so we don't need to be too harsh on judgment here i think the starting point is absolutely positive and it's great to have this tool so i think that the future is going to be brighter and this is going to be a valuable tool

Help us to make this transcription better! If you find an error, please submit a PR with your corrections.