WEBVTT

00:00.140 --> 00:00.460
Okay.

00:00.470 --> 00:06.320
So next, I want to show you how we can easily write some end to end tests for our microservices so

00:06.320 --> 00:12.100
that we can launch some tests against the real application and make sure everything is working as expected.

00:12.110 --> 00:16.460
Now, these tests are going to be different from unit tests or integration tests.

00:16.490 --> 00:22.850
These tests are actually going to test the production code running inside of a Docker container with

00:22.850 --> 00:25.790
all of the other dependencies also running.

00:25.790 --> 00:30.170
This kind of test is going to give us the most bang for our buck and make sure that the app is still

00:30.170 --> 00:31.490
functioning correctly.

00:31.490 --> 00:33.740
So let's go ahead and see how we can do this.

00:33.740 --> 00:38.720
I'm going to go ahead and create a new end to end folder in the root of the project, and I'm actually

00:38.720 --> 00:44.060
going to create a new package.json inside of this end to end folder.

00:44.060 --> 00:51.200
It's going to be a separate project all by itself so we can open up a new terminal and CD into the end

00:51.200 --> 00:56.030
to end folder and run npm init for the package name.

00:56.030 --> 01:03.200
I'll just call it sleeper end to end and we can continue through the rest of this setup instructions

01:03.200 --> 01:06.020
to generate a package.json.

01:06.020 --> 01:13.400
So let's cd back into the end to end folder and we can npm install dash D for development dependency.

01:13.430 --> 01:17.180
Make sure we install jest, which is what we're going to use to run the tests.

01:17.210 --> 01:23.600
TypeScript jest TypeScript itself and then the types for jest.

01:24.380 --> 01:34.160
So now that we have a package.json, go ahead and create a tsconfig.json so we can include a very basic

01:34.160 --> 01:37.550
set of instructions for how to compile our TypeScript code.

01:37.550 --> 01:42.680
So we'll include all the typescript inside of a new specs folder.

01:42.680 --> 01:47.780
So we'll create the specs folder and this is where we'll actually include all of our tests themselves.

01:47.780 --> 01:53.330
And then the rest of these options for TS config are just some basic out of the box options.

01:53.330 --> 02:02.480
So let's go back to our package.json and now we'll change the test command here to be jest and we can

02:02.480 --> 02:05.360
go ahead and create our first end to end file.

02:05.360 --> 02:10.460
Right now we'll just call it app dot end to end expects.

02:10.490 --> 02:17.990
We can just run an example test, so I'll say it should pass and we can just return.

02:17.990 --> 02:22.010
Expect true to be truthy.

02:22.010 --> 02:29.540
So we should definitely expect this test to pass so we can now run this from our end to end folder by

02:29.540 --> 02:35.960
running NPM test and we can see just running and it has correctly executed our test.

02:35.960 --> 02:36.830
So this is great.

02:36.830 --> 02:42.470
However, now we want to actually run our application and execute tests against it.

02:42.470 --> 02:48.020
So in order to do this, we're going to turn this end to end app into a Docker application that can

02:48.020 --> 02:53.690
run alongside of the other microservices in our application.

02:53.690 --> 02:57.770
So it can easily launch requests against them and make assertions.

02:57.770 --> 03:04.740
So to do this, we'll just simply create a Docker file in in the end to end folder and this will be

03:04.740 --> 03:06.450
a very basic Docker file.

03:06.450 --> 03:13.770
We will just extend Node Alpine here and then we'll set the working directory at user source app.

03:13.890 --> 03:23.580
Next we'll copy over our entire end to end folder and run npm install g npm to get NPM.

03:23.580 --> 03:28.140
Then we will install our dependencies by running npm install.

03:28.140 --> 03:35.430
And finally we can execute the command for this docker image which will simply be NPM test.

03:35.430 --> 03:42.630
To build this image, we'll run Docker, build tag end to end and go ahead and specify the current path

03:42.630 --> 03:47.060
at end to end, which is our current directory and we'll let the Docker image build.

03:47.070 --> 03:47.490
Okay.

03:47.490 --> 03:53.220
So now that we've built our Docker image, which contains all of our dependencies and test files, we

03:53.220 --> 03:56.130
can run it by running Docker run end to end.

03:56.790 --> 04:02.790
We can see the Docker image has run jest has run our apt end to end spec and has passed.

04:02.790 --> 04:09.300
So now that we have our end to end Docker image, we want to run the rest of our microservices alongside

04:09.300 --> 04:13.350
with it so that we can make real assertions in our end to end test.

04:13.350 --> 04:20.460
So let's go ahead and create a new Docker compose file in our end to end directory where we'll go ahead

04:20.460 --> 04:26.220
and define a new services list here and specify our first service.

04:26.220 --> 04:33.180
Of course we know the end to end container, so we'll go ahead and specify how to build this at our

04:33.180 --> 04:38.490
Docker file, which of course will just be in the current directory for the Docker file.

04:38.490 --> 04:46.560
And importantly, I want to mount our specs folder into the user source app specs directory.

04:46.560 --> 04:53.850
And that's so if we make changes to our tests, they will be reflected in real time as we run the container.

04:53.850 --> 04:56.430
So now we want to add the rest of our microservices.

04:56.430 --> 04:59.610
We can easily do this by going to our root docker compose.

05:00.070 --> 05:07.990
And let's go ahead and copy all of these services, including MongoDB, because of course, we will

05:07.990 --> 05:12.000
need to run a mongo instance for our application to function.

05:12.010 --> 05:18.130
However, now instead of building these services, we're going to use the production image directly

05:18.130 --> 05:21.670
to test against so we can specify an image here.

05:21.670 --> 05:30.790
We can get the image name from our templates reservations deployment file where we have the image name

05:30.910 --> 05:32.620
and paste it in.

05:33.140 --> 05:33.590
Now.

05:33.590 --> 05:36.140
We don't need to override a command.

05:36.140 --> 05:39.710
We can let the image run using the production node command.

05:39.740 --> 05:47.000
We will change the path to the file to go up one directory into app slash reservations and we have no

05:47.000 --> 05:50.000
need for a volume in this service.

05:50.000 --> 05:58.190
So I'm going to go ahead and copy this configuration and paste it for the rest of our services, including

05:58.220 --> 05:59.000
auth.

06:00.790 --> 06:05.440
Payments and notifications.

06:05.470 --> 06:11.150
Of course we'll make a change here to reference the auth image.

06:11.170 --> 06:17.140
The auth m file and open up our port at 3001 instead.

06:17.320 --> 06:23.290
We'll do the same thing for payments, so make sure we reference the correct path to payments and we

06:23.290 --> 06:25.140
have no need to open a port up.

06:25.150 --> 06:27.400
Same for notifications.

06:27.400 --> 06:32.850
So now we've defined all of the other services that will run alongside of our end to end container.

06:32.860 --> 06:38.080
However, now I want to make sure that when we start up the end to end container, the rest of our services

06:38.080 --> 06:39.610
are already running.

06:39.610 --> 06:42.340
So Docker Compose lets us do this easily.

06:42.340 --> 06:49.000
For our end to end definition here we can specify a new depends on list, where we provide the name

06:49.000 --> 06:53.800
of the services that we want to wait to be started before we start up.

06:53.800 --> 06:59.110
So I'll just say that the end to end container will depend on reservations.

07:00.090 --> 07:00.690
Off.

07:01.600 --> 07:02.740
Payments.

07:04.140 --> 07:11.250
Notifications and manga so that everything else starts up before we actually run our tests.

07:11.250 --> 07:18.900
So now we can test this out by running Docker compose up and to end in our end to end folder.

07:18.900 --> 07:25.950
And you can see here that it has gone ahead and created all of the microservices and is actually running

07:25.950 --> 07:30.760
and attaching to the end to end container and it has passed our one test.

07:30.780 --> 07:38.820
Additionally, we can show that our volume is working by changing expecting false to be true and rerunning

07:38.820 --> 07:39.450
the test.

07:39.480 --> 07:45.270
We should see that it now fails because we have volume mounted The updated tests which of course has

07:45.270 --> 07:50.420
incorrect logic and we can see that the container fails here because the test failed.

07:50.430 --> 07:56.400
So I'll go ahead and revert this test and now we can actually start making assertions against our real

07:56.400 --> 07:57.630
running services.

07:57.660 --> 07:59.940
The first test I want to write is the most basic.

07:59.940 --> 08:03.870
It's just called health check API end to end dot spec.

08:03.870 --> 08:06.330
And this is going to be exactly what it sounds like.

08:06.330 --> 08:10.380
It's going to be the health of the applications that we have.

08:10.410 --> 08:14.460
So I'll go ahead and create a new describe block and call it health here.

08:14.790 --> 08:21.330
So let's go ahead and open up a new function where we'll go ahead and describe each service we're going

08:21.330 --> 08:22.590
to test the health of.

08:22.620 --> 08:28.470
So we'll start with the reservations, which is our most important gateway into the system and change

08:28.470 --> 08:30.300
this to a test block.

08:30.300 --> 08:36.000
So all we're going to do in here is write asynchronous function, and all it's going to do is call,

08:36.000 --> 08:42.870
await Fetch, and we'll go ahead and specify the host name, which of course, we know since we're running

08:42.870 --> 08:49.140
inside of the same Docker compose, we are going to reach out with the service name that we defined

08:49.140 --> 08:49.590
here.

08:49.590 --> 08:54.930
So it will be just reservations and that will be on Port 3000.

08:54.930 --> 08:58.050
So we know we have a health check configured for reservations.

08:58.050 --> 09:04.450
So this should respond with an okay 200 status code and we can go ahead and check that here by setting

09:04.450 --> 09:06.700
it equal to response.

09:06.700 --> 09:15.550
And we can use just here to now expect that the response dot okay is a truth value, which only will

09:15.550 --> 09:18.460
be the case if we get A2XX status code.

09:18.460 --> 09:24.280
So let's go ahead and remove our other apt end to end spec and we can go ahead and test this out in

09:24.280 --> 09:30.910
our terminal by running Docker compose up so we can see that our health check has passed and we got

09:30.910 --> 09:32.320
a 200 status code.

09:32.350 --> 09:40.480
We can even go ahead and run Docker container logs on the reservations container to actually see the

09:40.480 --> 09:40.960
request.

09:40.960 --> 09:45.460
So let's do that Docker container logs and paste in the reservations.

09:45.460 --> 09:51.940
You can actually see our peanut logger here logging out the request from our integration tests with

09:51.940 --> 09:53.260
a 200 status code.

09:53.260 --> 09:58.120
So let's go ahead and repeat the same process for the other HTTP health check endpoint.

09:58.120 --> 10:06.550
We have the auth service, so we'll test the auth and expect the response to be, okay, we can save

10:06.550 --> 10:13.000
this and go ahead and retrigger the test by running Docker, compose up end to end.

10:13.000 --> 10:16.420
So you can see that our test failed because our fetch failed here.

10:16.420 --> 10:21.910
And you can see of course because my HTTP port is incorrect, it should be at 3001.

10:21.910 --> 10:27.580
And so now if we go ahead and try to rerun this test, we should see that it passes.

10:27.580 --> 10:34.060
So now both of our HTTP health checks are passing and we know if the service is starting up correctly

10:34.060 --> 10:39.580
and we don't have any runtime errors in the application because we have successfully opened up traffic

10:39.580 --> 10:40.660
in that container.

10:40.660 --> 10:41.020
Okay.

10:41.020 --> 10:45.760
So next we want to do the same health check on our other TCP microservices.

10:45.760 --> 10:48.850
However, they don't have an HTTP port exposed.

10:48.850 --> 10:50.800
It's just a TCP port.

10:50.800 --> 10:56.140
So in order to ping it correctly, we're going to go ahead and install some new dependencies to support

10:56.140 --> 10:56.680
this.

10:56.680 --> 10:59.800
Let's go ahead and install some development dependencies.

10:59.800 --> 11:02.830
So we're going to install a package called TCP ping.

11:02.860 --> 11:09.190
It's going to be able to ping a TCP connection based on the address that we provide, which is exactly

11:09.220 --> 11:14.170
what we want to support this, we're going to have to install some additional jest infrastructure.

11:14.170 --> 11:25.000
So we'll install TS, jest, TS, node and types slash node and the types for TCP ping.

11:25.000 --> 11:30.160
And since we're exposing additional ports in our other services now let's go ahead and specify that

11:30.160 --> 11:31.480
in our Docker compose.

11:31.480 --> 11:39.280
We'll go ahead and map the 3003 port on payments to our local 3003 and we'll do the same thing for notification.

11:39.280 --> 11:41.970
We'll go ahead and map 3004.

11:41.980 --> 11:49.090
So let's go ahead and now test our payments Microservice to start, we're going to accept a callback

11:49.090 --> 11:55.420
function and this time we're going to accept a new done parameter which which we can call to signify

11:55.420 --> 11:56.770
that we are done with the test.

11:56.770 --> 11:58.240
And it was successful.

11:58.240 --> 12:02.950
So let's go ahead and open up a function where we'll now call Ping and you can notice a.

12:02.990 --> 12:03.260
Here.

12:03.260 --> 12:05.720
I've imported ping from tcp ping.

12:05.750 --> 12:10.160
Ping takes an options object where we specify the address of the microservice.

12:10.160 --> 12:16.700
So we know this is payments as we've defined in our docker compose and the port will be at 3003.

12:16.730 --> 12:23.270
Next we receive a callback that gets access to an error object if one is thrown.

12:23.270 --> 12:26.060
So we will check to see if there is an error.

12:26.090 --> 12:27.920
Then we will call the jest function.

12:27.920 --> 12:30.500
Fail to immediately fail the test.

12:30.530 --> 12:34.850
Otherwise we will call done and signify that the test was successful.

12:34.880 --> 12:41.630
Next, in order to have jest properly compile our TypeScript code in this file, we will make use of

12:41.630 --> 12:44.030
the JS package we installed.

12:44.030 --> 12:47.180
We need to create a new file an end to end called.

12:47.860 --> 12:55.090
Jazz dot config dot ts and we'll have a module dot exports set equal to an object here where we specify

12:55.090 --> 12:57.280
the preset is TS jest.

12:57.310 --> 13:05.710
Now we can rerun Docker, compose up end to end and signify dash dash build to tell docker compose to

13:05.710 --> 13:09.490
rebuild our end to end container and install our new dependencies.

13:09.490 --> 13:15.370
You can see our health check to our payment service is successful and our test is passing, which shows

13:15.370 --> 13:19.270
that our service is up and running and responding to traffic.

13:19.270 --> 13:25.720
Let's finish our health check tests up by copying this payments block and creating one more for our

13:25.720 --> 13:27.160
last microservice.

13:27.190 --> 13:29.470
The notifications microservice.

13:29.500 --> 13:34.660
The address will change to notifications and the port will be at 3004.

13:34.690 --> 13:37.150
We can verify this works by running Docker.

13:37.150 --> 13:38.830
Compose up end to end.

13:38.860 --> 13:43.390
You can see that all of our services are responding to our health check successfully.

13:43.390 --> 13:47.990
Okay, so now that we've verified the health of our application, let's test out some of the functions.
