You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: context-aware-reader.md
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# Context-aware readers
2
2
3
-
**[You can find all the code here](https://github.com/quii/learn-go-with-tests/tree/master/q-and-a/context-aware-reader)**
3
+
**[You can find all the code here](https://github.com/quii/learn-go-with-tests/tree/main/q-and-a/context-aware-reader)**
4
4
5
5
This chapter demonstrates how to test-drive a context aware `io.Reader` as written by Mat Ryer and David Hernandez in [The Pace Dev Blog](https://pace.dev/blog/2020/02/03/context-aware-ioreader-for-golang-by-mat-ryer).
Copy file name to clipboardExpand all lines: context.md
+31-31Lines changed: 31 additions & 31 deletions
Original file line number
Diff line number
Diff line change
@@ -1,16 +1,16 @@
1
1
# Context
2
2
3
-
**[You can find all the code for this chapter here](https://github.com/quii/learn-go-with-tests/tree/master/context)**
3
+
**[You can find all the code for this chapter here](https://github.com/quii/learn-go-with-tests/tree/main/context)**
4
4
5
-
Software often kicks off long-running, resource-intensive processes (often in goroutines). If the action that caused this gets cancelled or fails for some reason you need to stop these processes in a consistent way through your application.
5
+
Software often kicks off long-running, resource-intensive processes (often in goroutines). If the action that caused this gets cancelled or fails for some reason you need to stop these processes in a consistent way through your application.
6
6
7
-
If you don't manage this your snappy Go application that you're so proud of could start having difficult to debug performance problems.
7
+
If you don't manage this your snappy Go application that you're so proud of could start having difficult to debug performance problems.
8
8
9
9
In this chapter we'll use the package `context` to help us manage long-running processes.
10
10
11
-
We're going to start with a classic example of a web server that when hit kicks off a potentially long-running process to fetch some data for it to return in the response.
11
+
We're going to start with a classic example of a web server that when hit kicks off a potentially long-running process to fetch some data for it to return in the response.
12
12
13
-
We will exercise a scenario where a user cancels the request before the data can be retrieved and we'll make sure the process is told to give up.
13
+
We will exercise a scenario where a user cancels the request before the data can be retrieved and we'll make sure the process is told to give up.
14
14
15
15
I've set up some code on the happy path to get us started. Here is our server code.
16
16
@@ -95,17 +95,17 @@ Let's add a new test where we cancel the request before 100 milliseconds and che
95
95
t.Run("tells store to cancel work if request is cancelled", func(t *testing.T) {
@@ -116,7 +116,7 @@ From the [Go Blog: Context](https://blog.golang.org/context)
116
116
117
117
> The context package provides functions to derive new Context values from existing ones. These values form a tree: when a Context is canceled, all Contexts derived from it are also canceled.
118
118
119
-
It's important that you derive your contexts so that cancellations are propagated throughout the call stack for a given request.
119
+
It's important that you derive your contexts so that cancellations are propagated throughout the call stack for a given request.
120
120
121
121
What we do is derive a new `cancellingCtx` from our `request` which returns us a `cancel` function. We then schedule that function to be called in 5 milliseconds by using `time.AfterFunc`. Finally we use this new context in our request by calling `request.WithContext`.
122
122
@@ -132,7 +132,7 @@ The test fails as we'd expect.
132
132
133
133
## Write enough code to make it pass
134
134
135
-
Remember to be disciplined with TDD. Write the _minimal_ amount of code to make our test pass.
135
+
Remember to be disciplined with TDD. Write the _minimal_ amount of code to make our test pass.
Does it make sense for our web server to be concerned with manually cancelling `Store`? What if `Store` also happens to depend on other slow-running processes? We'll have to make sure that `Store.Cancel` correctly propagates the cancellation to all of its dependants.
264
+
Does it make sense for our web server to be concerned with manually cancelling `Store`? What if `Store` also happens to depend on other slow-running processes? We'll have to make sure that `Store.Cancel` correctly propagates the cancellation to all of its dependants.
265
265
266
-
One of the main points of `context` is that it is a consistent way of offering cancellation.
266
+
One of the main points of `context` is that it is a consistent way of offering cancellation.
267
267
268
268
[From the go doc](https://golang.org/pkg/context/)
269
269
@@ -281,7 +281,7 @@ Feeling a bit uneasy? Good. Let's try and follow that approach though and instea
281
281
282
282
We'll have to change our existing tests as their responsibilities are changing. The only thing our handler is responsible for now is making sure it sends a context through to the downstream `Store` and that it handles the error that will come from the `Store` when it is cancelled.
283
283
284
-
Let's update our `Store` interface to show the new responsibilities.
284
+
Let's update our `Store` interface to show the new responsibilities.
We have to make our spy act like a real method that works with `context`.
336
+
We have to make our spy act like a real method that works with `context`.
337
337
338
-
We are simulating a slow process where we build the result slowly by appending the string, character by character in a goroutine. When the goroutine finishes its work it writes the string to the `data` channel. The goroutine listens for the `ctx.Done` and will stop the work if a signal is sent in that channel.
338
+
We are simulating a slow process where we build the result slowly by appending the string, character by character in a goroutine. When the goroutine finishes its work it writes the string to the `data` channel. The goroutine listens for the `ctx.Done` and will stop the work if a signal is sent in that channel.
339
339
340
340
Finally the code uses another `select` to wait for that goroutine to finish its work or for the cancellation to occur.
341
341
342
-
It's similar to our approach from before, we use Go's concurrency primitives to make two asynchronous processes race each other to determine what we return.
342
+
It's similar to our approach from before, we use Go's concurrency primitives to make two asynchronous processes race each other to determine what we return.
343
343
344
344
You'll take a similar approach when writing your own functions and methods that accept a `context` so make sure you understand what's going on.
345
345
@@ -385,7 +385,7 @@ Our happy path should be... happy. Now we can fix the other test.
385
385
386
386
## Write the test first
387
387
388
-
We need to test that we do not write any kind of response on the error case. Sadly `httptest.ResponseRecorder` doesn't have a way of figuring this out so we'll have to role our own spy to test for this.
388
+
We need to test that we do not write any kind of response on the error case. Sadly `httptest.ResponseRecorder` doesn't have a way of figuring this out so we'll have to role our own spy to test for this.
We can see after this that the server code has become simplified as it's no longer explicitly responsible for cancellation, it simply passes through `context` and relies on the downstream functions to respect any cancellations that may occur.
459
+
We can see after this that the server code has become simplified as it's no longer explicitly responsible for cancellation, it simply passes through `context` and relies on the downstream functions to respect any cancellations that may occur.
460
460
461
461
## Wrapping up
462
462
@@ -474,13 +474,13 @@ We can see after this that the server code has become simplified as it's no long
474
474
475
475
> If you use ctx.Value in my (non-existent) company, you’re fired
476
476
477
-
Some engineers have advocated passing values through `context` as it _feels convenient_.
477
+
Some engineers have advocated passing values through `context` as it _feels convenient_.
478
478
479
-
Convenience is often the cause of bad code.
479
+
Convenience is often the cause of bad code.
480
480
481
-
The problem with `context.Values` is that it's just an untyped map so you have no type-safety and you have to handle it not actually containing your value. You have to create a coupling of map keys from one module to another and if someone changes something things start breaking.
481
+
The problem with `context.Values` is that it's just an untyped map so you have no type-safety and you have to handle it not actually containing your value. You have to create a coupling of map keys from one module to another and if someone changes something things start breaking.
482
482
483
-
In short, **if a function needs some values, put them as typed parameters rather than trying to fetch them from `context.Value`**. This makes is statically checked and documented for everyone to see.
483
+
In short, **if a function needs some values, put them as typed parameters rather than trying to fetch them from `context.Value`**. This makes is statically checked and documented for everyone to see.
Copy file name to clipboardExpand all lines: http-handlers-revisited.md
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# HTTP Handlers Revisited
2
2
3
-
**[You can find all the code here](https://github.com/quii/learn-go-with-tests/tree/master/q-and-a/http-handlers-revisited)**
3
+
**[You can find all the code here](https://github.com/quii/learn-go-with-tests/tree/main/q-and-a/http-handlers-revisited)**
4
4
5
5
This book already has a chapter on [testing a HTTP handler](http-server.md) but this will feature a broader discussion on designing them, so they are simple to test.
Copy file name to clipboardExpand all lines: io.md
+2-2Lines changed: 2 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# IO and sorting
2
2
3
-
**[You can find all the code for this chapter here](https://github.com/quii/learn-go-with-tests/tree/master/io)**
3
+
**[You can find all the code for this chapter here](https://github.com/quii/learn-go-with-tests/tree/main/io)**
4
4
5
5
[In the previous chapter](json.md) we continued iterating on our application by adding a new endpoint `/league`. Along the way we learned about how to deal with JSON, embedding types and routing.
Finally, we can get the amazing payoff we wanted by removing the `Seek` call from `RecordWin`. Yes, it doesn't feel much, but at least it means if we do any other kind of writes we can rely on our `Write` to behave how we need it to. Plus it will now let us test the potentially problematic code separately and fix it.
831
831
832
-
Let's write the test where we want to update the entire contents of a file with something that is smaller than the original contents.
832
+
Let's write the test where we want to update the entire contents of a file with something that is smaller than the original contents.
Copy file name to clipboardExpand all lines: maps.md
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# Maps
2
2
3
-
**[You can find all the code for this chapter here](https://github.com/quii/learn-go-with-tests/tree/master/maps)**
3
+
**[You can find all the code for this chapter here](https://github.com/quii/learn-go-with-tests/tree/main/maps)**
4
4
5
5
In [arrays & slices](arrays-and-slices.md), you saw how to store values in order. Now, we will look at a way to store items by a `key` and look them up quickly.
Copy file name to clipboardExpand all lines: mocking.md
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# Mocking
2
2
3
-
**[You can find all the code for this chapter here](https://github.com/quii/learn-go-with-tests/tree/master/mocking)**
3
+
**[You can find all the code for this chapter here](https://github.com/quii/learn-go-with-tests/tree/main/mocking)**
4
4
5
5
You have been asked to write a program which counts down from 3, printing each number on a new line (with a 1 second pause) and when it reaches zero it will print "Go!" and exit.
0 commit comments