[args]
The available commands for execution are listed below.
The primary workflow commands are given first, followed by
less common or more advanced commands.
Main commands:
init Prepare your working directory for other commands
validate Check whether the configuration is valid
plan Show changes required by the current configuration
apply Create or update infrastructure
destroy Destroy previously-created infrastructure
```
----
### What we have learned
* Go belongs to the C/Java syntactic family
* There are packages and imports, such as in Java
* Hello World example
* Crosscompiling in action
* Crosscompile Configurations
* How to build binaries for huge projects
* `opentofu` tool
----
### Further readings
* Crosscompile
* [golangcookbook.com/chapters/running/cross-compiling/0](https://golangcookbook.com/chapters/running/cross-compiling/0)
* Crosscompile Configuration
* [go.dev/doc/install/source#environment](https://go.dev/doc/install/source#environment)
* Open Tofu
* [github.com/opentofu/opentofu](https://github.com/opentofu/opentofu)
* [github.com/opentofu/opentofu/blob/main/BUILDING.md](https://github.com/opentofu/opentofu/blob/main/BUILDING.md)
Note: speaker notes FTW!
---
----
## Hello World Dockerized
This task is supposed to demonstrate Docker image build for Go applications.
The program should print the text `Hello World! This is Go.` to the standard output in a docker container.
----
### Too fast? Find source code here:
* [github.com/go-gurus/go_tour_src/tree/main/hello-world-dockerized](https://github.com/go-gurus/go_tour_src/tree/main/hello-world-dockerized)
----
----
### Solution
```golang
// main.go
package main
import "fmt"
func main() {
fmt.Println("Hello World! This is Go.")
}
```
----
```Dockerfile
# Dockerfile
# build stage
FROM golang:1.17.6-alpine AS build
RUN mkdir -p /app
WORKDIR /app
# app src
COPY . .
RUN GOOS=linux GOARCH=amd64 go build -o /bin/app main.go
# result stage
FROM scratch
COPY --from=build /bin/app /bin/app
ENTRYPOINT ["/bin/app"]
```
----
### Building and executing Go code
* build docker image
```bash
$ docker build -t hello-image .
```
* inspect image size
```bash
$ docker images hello-image
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-image latest d23a3532deaf 4 minutes ago 1.77MB
```
* run container
```bash
$ docker run --rm -it --name hello-con hello-image
Hello World! This is Go.
```
----
### What we have learned
* How to write a Go Dockerfile
* Use build stages for Go applications
* Go Docker image sizes
* faster build and deployment time
* less server/cluster workload and resource consumption
----
### Further readings
* Golang Docker file
* [hub.docker.com/_/golang](https://hub.docker.com/_/golang)
---
----
## Testing
In this task, you will learn about writing tests in Go by developing a prime tester in TDD-style.
----
### Too fast? Find source code here:
* [github.com/go-gurus/go_tour_src/tree/main/prime-checker](https://github.com/go-gurus/go_tour_src/tree/main/prime-checker)
----
----
### Solution
* lets write a simple `main.go` file
```go
// main.go
package main
func main() {
}
```
----
* now, Lets write a test to specify what we expect from the prime checker yet to be developed.
```golang
// main_test.go
package main
import "testing"
func TestPrimeCheckerTheNaiveWay(t *testing.T) {
t.Run("should return FALSE when no prime number given", func(t *testing.T) {
if IsPrime(4) == true {
t.Fatal("Reported IsPrime=true for 4")
}
})
t.Run("should return TRUE when prime number given", func(t *testing.T) {
if IsPrime(7) == false {
t.Fatal("Reported IsPrime=false for 7")
}
})
}
```
----
### Executing tests
```bash
go test main.go main_test.go
./main_test.go:9:6: undefined: IsPrime
./main_test.go:15:6: undefined: IsPrime
./main_test.go:35:14: undefined: IsPrime
FAIL command-line-arguments [build failed]
FAIL
```
The test will fail, because the function `IsPrime` is yet to be implemented.
> We will learn a better way to run Go tests later
----
### Implement the (naive) IsPrime function
```golang
// main.go
// ...
import (
"math"
)
func IsPrime(value int) (result bool) {
for i := 2; i <= int(math.Floor(math.Sqrt(float64(value)))); i++ {
if value %i == 0 {
return false
}
}
return value > 1
}
// ...
```
* run the tests again
```bash
go test main.go main_test.go
ok command-line-arguments 0.102s
```
----
### Table-driven tests
Cut down redundancy in your tests:
```golang
// main_test.go
// ...
func TestPrimeCheckerTableDriven(t *testing.T) {
cases := []struct {
input int
expectedResult bool
}{
{1, false},
{2, true},
{3, true},
{4, false},
{7, true},
}
for _, e := range cases {
t.Run("Should return expected result ", func(t *testing.T) {
result := IsPrime(e.input)
if result != e.expectedResult {
t.Fatalf("Unexpected Result input=%d expected=%t actual=%t",
e.input,
e.expectedResult,
result)
}
})
}
}
```
----
### Code Coverage
* now lets execute the tests with coverage
```bash
$ go test -cover main.go main_test.go
ok command-line-arguments 0.191s coverage: 100.0% of statements
```
----
* lets add also a report
```bash
go test -coverprofile=coverage.out main.go main_test.go
```
```text
mode: set
/Users/grohmio/repos/cc/gophers/golang-for-developers/examples/03-prime-checker/main.go:7.14,8.2 0 0
/Users/grohmio/repos/cc/gophers/golang-for-developers/examples/03-prime-checker/main.go:10.39,11.67 1 1
/Users/grohmio/repos/cc/gophers/golang-for-developers/examples/03-prime-checker/main.go:16.2,16.18 1 1
/Users/grohmio/repos/cc/gophers/golang-for-developers/examples/03-prime-checker/main.go:11.67,12.19 1 1
/Users/grohmio/repos/cc/gophers/golang-for-developers/examples/03-prime-checker/main.go:12.19,14.4 1 1
```
----
* now lets use the go `coverage` tool to generate a graphical report
```bash
go tool cover -html=coverage.out main.go main_test.go
```

----
### What we have learned
* How to use the Go testing package
* How to run tests
* Write our first Go function with in and out parameters
* Basic loops and branching
* How to show code coverage
* How to create coverage reports
---
----
## Templating
In this task we want to write a small program that uses the GO templating engine to create an output for 3 different unit systems.
----
### Too fast? Find source code here:
* [github.com/go-gurus/go_tour_src/tree/main/templating](https://github.com/go-gurus/go_tour_src/tree/main/templating)
----
### the task

----
### motivation
Imagine you need to present data in a well-formatted output, e.g. in `text` or in files like `html`, `json`, `xml` or `yaml`.
----
### packages
* [pkg.go.dev/text/template](https://pkg.go.dev/text/template)
* [pkg.go.dev/html/template](https://pkg.go.dev/html/template)
Both packages are based on the same basic framework and offer similar functionalities, but are specialised for different purposes.
----
### text/template
* generic templating system for processing plain text
* generation of `text` files, e.g. `YAML`, `JSON`, `INI`, `sh`, `sql` ...
* general data transformation where no special security precautions are required
* no automatic escape logic for special characters
* greater flexibility in output (no HTML-specific restrictions)
----
### html/template
* templating system developed for generating secure `HTML` output
* creation of web pages or emails with `HTML` content
* automatic escape logic, `<`, `>`, `&`, `’` converted into `HTML` entities
* recognises certain `HTML` contexts (e.g. tags, attributes, JavaScript), adapts the escaping strategy
* prevent `XSS`, malicious scripts, displayed securely in browser
* overall: protection against security vulnerabilities in dynamic content
----
### advantages
* fast and lightweight
* part of the GO standard library, no need for additional dependencies
* type safety, strict type-checking during template execution reduces runtime errors
* extensibility, you can define custom template functions to extend functionality
----
### the 1st task
In the first part of the task, we want to create a formatted text output that shows us data in three different systems of units, the metric, the imperial or US system and the maritime and aeronautical system.
----
### unit systems
System |
Length |
Speed |
Metric |
m, km |
m/s, km/h |
Imperial/US |
in ("), mi |
ips, mph |
Maritime/Aviation |
nm |
kn |
----
----
### text/template
```golang
//main.go
package main
import (
"os"
"text/template"
)
type Data struct {
Distance float64
DistanceUnit string
Speed float64
SpeedUnit string
Time float64
TimeUnit string
}
...
```
----
```golang
//main.go
...
func main() {
tmpl, err := template.New("example").Parse(`
Distance: {{.Distance}} {{.DistanceUnit}}
Speed: {{.Speed}} {{.SpeedUnit}}
You are travelling at a speed of {{.Speed}} {{.SpeedUnit}}.
You will cover a distance of {{.Distance}} {{.DistanceUnit}} in {{.Time}} {{.TimeUnit}}.
`)
if err != nil {
panic(err)
}
...
}
```
----
```golang
//main.go
...
func main() {
...
// metric system
metric_data := Data{1000, "km", 100, "km/h", 10, "h"}
err = tmpl.Execute(os.Stdout, metric_data)
if err != nil {
panic(err)
}
// imperial system
imperial_data := Data{621.371, "mi", 62.1371, "mph", 10, "h"}
err = tmpl.Execute(os.Stdout, imperial_data)
if err != nil {
panic(err)
}
}
```
----
```golang
//main.go
...
func main() {
...
//maritime/aviation system
maritime_data := Data{539.957, "nm", 53.9957, "kn", 10, "h"}
err = tmpl.Execute(os.Stdout, maritime_data)
if err != nil {
panic(err)
}
}
```
----
```sh
$ go run main.go
Distance: 1000 km
Speed: 100 km/h
You are travelling at a speed of 100 km/h.
You will cover a distance of 1000 km in 10 h.
Distance: 621.371 mi
Speed: 62.1371 mph
You are travelling at a speed of 62.1371 mph.
You will cover a distance of 621.371 mi in 10 h.
Distance: 539.957 nm
Speed: 53.9957 kn
You are travelling at a speed of 53.9957 kn.
You will cover a distance of 539.957 nm in 10 h.
```
----
### the 2nd task
In the second half of the task we will try to create an `HTML` file that is exposed to an `XSS` attack. For this we will first use the package `text/template` in order to later apply and illustrate the functionality of the package `html/template`.
----
Lets write a new file.
```golang
//main.go
package main
import (
"text/template"
"os"
)
type Data struct {
Distance float64
DistanceUnit string
Speed float64
SpeedUnit string
Time float64
TimeUnit string
}
...
```
----
```golang
//main.go
...
func main() {
tmpl, err := template.New("example").Parse(`
Travel Information
Travel Information
Distance: {{.Distance}} {{.DistanceUnit}}
Speed: {{.Speed}} {{.SpeedUnit}}
You are travelling at a speed of {{.Speed}} {{.SpeedUnit}}.
You will cover a distance of {{.Distance}} {{.DistanceUnit}} in {{.Time}} {{.TimeUnit}}.