2.11 Consolidate the Validation Process Into the Application
We're moving our way towards a single web application that matches our expectations. We're reaching the point where we can safely test the whole login procedure at once. But we still need to clean up some rough edges before doing so.
1.Introduction2 lessons, 07:43
2.Creating the API Server12 lessons, 2:10:56
3.A Client Demonstration App2 lessons, 20:49
4.Conclusion1 lesson, 01:35
2.11 Consolidate the Validation Process Into the Application
As you can see in the diagram, we have progressed a lot further. We have the login method here, as you can see. It provides a service as usual. At the end, we'll submit new data via the POST route. We validate and authenticate the user, set the cookie accordingly, then the service ticket. And after issuing the service ticket, we need to validate it. We're gonna use the p3/serviceValidate method. It is available in the protocol specification. Let me just quickly fetch it. So, let me just fetch p3/serviceValidate. You can see in section 2.8 that this is the latest version specification for validating the service. So, we're gonna use this route instead of just plain, old /serviceValidate without this selected text. So here is a standard test we have included in the source code. This API validate test will counter this Sinatra app in regards to validating the service and respective service ticket. We're going to spawn a new user. and we also have a service string as usual. Now we're going to clear the cookies before anything else, and we will perform a login with this user. After that, we're going to perform our tests. We're going to reach out to this sprout, which I've mentioned before that it has to be this one. Then the service and ticket will be provided along with the get request. We should have a 200 status code, and it should also be an XML file. With that said, let's run the tests, and you will see that there is no such route. There you go. A 404 code is given. Let's go ahead and open that app file. Okay. Now at the end of the public methods, I'm going to include another one called /p3/servicevalidate. We'll pass a block to it. And you will see that indeed it is going to return a status code of 200. So let's move on to the next step. Basically, we want to return an XML file. So let's run the tests now. Okay, and you can see that the current content type is set to text HTML. Let's change that by using the content_type method available in Sinatra, and use XML. There you go. If we run the tests now, they will pass. Well, in order to fully fulfill the coverage of the specification, we probably should add more tests. But for the sake of simplicity, I'm going to just provide the code that should be here. We're going to use the builder method that will basically act as Haml for HTML, but this one is for XML. So I'm going to provide a serviceValidate template back to builder. We also need to have some variables available in this template. Which variables should we add? Well, we should have a user variable, which is going to be the result of a particular service and the respective user variable. This service variable, let's take care of that right away. I'll call Api::Services::Validate.new. We need some parameters along, but let's go ahead and consult what we should provide, namely, the service and the service ticket name. [BLANK_AUDIO] How do we reach to those? Well, first of all, the service is rather easy. We just reach out to params[:service] because it's provided in the URL. And speaking of which, we also have the service ticket name. Let's provide params[:ticket], and it's just as simple as that. Let me just re-indent these really quick so that it's just a lot easier to read. We're gonna call that service, and from here, we need to check whether it was successful or not. So if status equals ok, then we should do something. Otherwise, we should do another thing. What's most important is that we will always return an XML content, so this will always be part of the standard route. There's no condition to whether it is XML or not. And the user will always be part of the true condition. The user will only be displayed in this condition. At the end, we will always have the builder template being rendered. Now for the successful condition, we will provide a success equals true, which means that success will be nil in case we don't define it like we won't in the else condition. Instead, we're going to provide an error message, which should be one of the many different ones available in this specification. However, it's not really that important as of now, so what I'm going to do is just to provide an UNKNOWN_ERROR here. If you want to, you can pass one of them available,] such as invalid ticket. Let's say this is a possibility. If you want to, you can complement the information in the error instance variable as you see fit. This one involves a lot more complexity in our service. And I didn't want to confuse you a lot more than this already is. So instead, I'm going to be simple and stick to the successful condition as the most complex one. We wanna have a user instance variable, as well as a success variable set to true. There's also one thing that we should do, and that is to provide a status code in the error message. In this case, we can assure ourselves that only the successful case will have the 200 status code. Let's run the tests, by the way, while we're at it. Well, you can see two different things at first. For one thing, we were expecting an XML file and we're not, so what happened? Let's start with pasting this at the very bottom, and hopefully this should solve one of the issues. Unfortunately for us, it seems that this doesn't solve anything. So for that reason, I'm gonna go to the top of the class, and I'm going to configure the test environment. The reason for that is very simple. I want to set a couple of variables in order for us to show the real reason behind the error. As you know, we got an HTML content type along with a 500 status code. This means that we had an error inside the code. So what I'm gonna do is I'm gonna type raise_errors to true. And set show_exceptions to false. [BLANK_AUDIO] Now if you recall about Sinatra, we will need to pass in a rack environment in order to enable the test environment. So I'm going to modify my mapping to run the tests. So I'll use this command that I usually use. And this time, I'm going to pass in RACK_ENV equals test, and then bundle exec rake. Press the Enter key too. And now I can run the tests, and most likely we will have two different errors. There you go. Now this is a lot different. You can see that we are expecting two arguments, but we only got one. The same goes for the previous one. So that's why it wasn't working. We need to make sure that we pass both arguments. Let's go over the Validate class once again. You can see that in this particular case, I don't have keyword arguments. I just have direct values. So I'll just remove the keywords all the way like so and run the tests. Let's see what errors we get now. Okay, so now it is a lot different. You can see that in both of the cases, we don't have that serviceValidate.builder template. That's easy to fix. All we need to do is go to the app folder under views, create that serviceValidate.builder template. I'm gonna take the chance and open it in a new tab. But now, most importantly, we need to run the tests to make sure they pass. Only one of them is failing. As you can see, we are going through the 201 status code. Let's go to our application, and you can see that the service.status is not ok. So what happened here? It appears that the service ticket is not found. Otherwise, we would have that status variable. So let's take a look at that and see what went wrong. So in order to debug this really quick, I'm gonna go ahead and establish a binding with pry. From here, we'll be able to validate the service and check the reason for this to be happening. Let's stick to chance and look at the various different variables that we have. Let's check the Service class. You can see that we have a service instance variable and a service_ticket_name. But we don't have any service_ticket at all. Let's take a look at all of the ServiceTickets. I'm going to type in this instruction. You can see that we have a ServiceTicket, only one, with that exact service ticket name but there is no service attached to it. So this means that we have a problem on the inside when creating that service. So for that reason, we'll need to revisit old code. Let's take a look at the test really quick. The perform_login method should also take a service. After all, this reference is necessary in order for us to retrieve the actual service and compare it to the ticket. Let's go to the test helper. And at the end of the file, we should also provide a service here. So service, like so. I'm just going to provide a default value so that other tests don't break. Now, let's run the tests again. And this time, we still have an error. Let's see what went wrong this time. Remember that these things can happen, so be patient when facing these kinds of difficulties. In this case, it seems we have an invalid URI error. So what should we do? Before we do anything, it's important to realize which test is causing this error. If you take a close look, you will see that it is in the API test. So we'll need to go there, API test. And at the end of it all, you will see the warm login test here. The perform_login method here is expecting a service variable here. So I'll provide that same string as you see here. So I'll just pass in there. Okay, there you go. Now I'm going to run the tests. Okay, so apparently, this was easy to fix. When you have such an error regarding URIs, most likely something is missing. Indeed, it was. So in this case, all we want to do is make sure that the service parameter is passed in. However, when you go back to the previous test, you will see that this won't work. And why is that? Well, for that, I'm going to establish a binding using pry. Let's run the test here, and you will see something peculiar. In this specific test, we will see that the last response is indeed an XML one, but the status is 201. Now, we would be assuming that the service ticket is okay. Well, the service variable is there, as well as the ticket. So if we take a look at the service ticket, you see that the service ticket's there. However, if we take a look at ServiceTicket.all, you will see that service is nil when it shouldn't. This can only mean that the login process is faulty. Let's go to the login service, and here we should provide a service ticket with the appropriate service. So let's go there. As you can see, the generate_service_ticket method is flawed. We need to pass in the service variable here, which will be a particular value. Where is it? There you go. You can see that we have that service instance variable available. Let's go there and pass in service. Let's see if this works by running the tests. Okay, you can see that indeed we are having some trouble. That method doesn't exist. Oh, because we need to pass in the instance variable. Let's run the tests again. Let me just comment that out. And we still have that 201 status code. Let's see why that is. Taking a look at the post route, you will see that when calling the service, we are not passing that service variable. Let's make sure we do. Service should be equivalent to the service we already have. Where is it? Well, params and then service. Let's see if this now works. Let's run the tests. And as you can see, up until now, we have no errors. Let's check if this one is working too, and it is. Wonderful job. Okay, so this is what was needed. The service variable was hanging around, and it got lost in translation. So, let me just remove that binding, there you go, in line 18. Now, running the whole set of tests, you can see that all of them are green. Now, in order to finish all of this, we'll need to make sure that content of the XML file is correct. And we will also take the chance to integrate everything and test it live.