Obsah
2. Ukázky použití původního expect a varianty vytvořené v Pythonu
3. Balíčky go-expect, gexpect a GoExpect
4. Nejjednodušší použití balíčku go-expect – test obsahu standardního výstupu vybrané aplikace
5. Nastavení doby čekání při testu standardního výstupu aplikace
6. Podobný příklad s testem výstupu příkazu curl
7. Automatické ovládání aplikace díky koordinaci jejího standardního výstupu a vstupu
8. Programové ovládání interpretru jazyka Python
9. Reakce na několik alternativních řetězců na výstupu aplikace
10. Testování aplikací s textovým rozhraním kombinací balíčků testing a go-expect
11. Složitější příklad – test korektnosti výpočtů prováděných intepretrem Pythonu
13. Přepis příkladu volajícího příkaz curl
14. Ovládání interaktivní hry spuštěné přes telnet
15. Ovládání interpretru Pythonu
16. Detekce, který interpret Pythonu byl spuštěn
17. Kombinace knihoven testing a gexpect
18. Test korektnosti výpočtů prováděných intepretrem Pythonu podruhé
19. Repositář s demonstračními příklady
1. Nástroje typu expect
Při automatizaci úloh, v nichž je nutné kooperovat s interaktivními nástroji ovládanými ze standardního vstupu (telnet, ssh, ftp, všechny interpretry, gdb, různé instalační skripty atd. atd.), se mnohdy používá nástroj expect. S využitím tohoto nástroje je možné specifikovat a následně spouštět operace typu „pokud se na terminálu objeví text ‚login‘, pošli aplikaci na její standardní vstup obsah proměnné login“, popř. je dokonce možné provést rozeskoky podle toho, jaká zpráva se na terminálu objeví. I z tohoto důvodu se expect používá pro testování aplikací, například v telcom oblasti. Nástroj expect je skutečně všestranně použitelný, ovšem má také několik nevýhod. Jednou z nich je, že je naprogramován v dnes již poněkud obstarožním programovacím jazyce TCL a i skripty pro expect je tedy nutné v TCL vytvářet.
To může být pro současné programátory poněkud těžký oříšek a navíc je relativně složité zařadit expect například do integračních testů vyvinutých v odlišném programovacím jazyce. Dnes ovšem již existuje větší množství alternativních implementací prakticky stejné funkcionality, jakou nabízí samotný expect. Pro prakticky jakýkoli rozšířený programovací jazyk najdeme alespoň jednu alternativní implementaci. Týká se to pochopitelně i programovacího jazyka Go, pro který existuje knihoven hned několik. A právě těmito knihovnami – přesněji řečeno dvěma knihovnami z rozsáhlejší nabídky – se budeme v dnešní části seriálu o programovacím jazyce Go podrobněji zabývat.
2. Ukázky použití původního expect a varianty vytvořené v Pythonu
Podívejme se však nejprve na typický příklad použití nástroje expect. Tento příklad najdete například na Wikipedii, ale i v mnoha dalších článcích, které se tímto užitečným nástrojem zabývají. Ve skriptu je provedeno připojení (přes telnet) na vzdálený stroj. Ve chvíli, kdy vzdálený stroj čeká na zadání uživatelského jména, je mu posláno jméno (resp. přesněji řečeno jakýkoli text) uložené v proměnné my_user_id. Dále se na výzvu pro zadání hesla naprosto stejným způsobem předá heslo z proměnné nazvané my_password. Nakonec se očekává zobrazení výzvy (zde ve tvaru %); v této chvíli se na vzdálený stroj pošle specifikovaný příkaz a spojení se ukončí příkazem „exit“:
spawn telnet $remote_server expect "username:" # Send the username, and then wait for a password prompt. send "$my_user_id\r" expect "password:" # Send the password, and then wait for a shell prompt. send "$my_password\r" expect "%" # Send the prebuilt command, and then wait for another shell prompt. send "$my_command\r" expect "%" # Capture the results of the command into a variable. This can be displayed, or written to disk. set results $expect_out(buffer) # Exit the telnet session, and wait for a special end-of-file character. send "exit\r" expect eof
Nepatrně složitější příklad (taktéž ovšem velmi typický – najdete ho v prakticky každém tutoriálu o expectu) se pokusí připojit na vzdálený stroj přes ssh. Tentokrát je ovšem proveden rozeskok na základě toho, jaká informace se vypíše. Při prvním připojení se totiž ssh zeptá, zda se skutečně připojuje k ověřenému stroji (odpovídáme zde automaticky „yes“, což ovšem není příliš bezpečné), při dalším připojení je již adresa zapamatována, takže se ssh přímo zeptá na heslo. Pokud nedojde ani k jedné variantě, je připojení ihned ukončeno příkazem exit:
set timeout 60 spawn ssh $user@machine while {1} { expect { eof {break} "The authenticity of host" {send "yes\r"} "password:" {send "$password\r"} "*\]" {send "exit\r"} } } wait close $spawn_id
Pro zajímavost se ještě podívejme na způsob implementace funkcionality nástroje expect v Pythonu, konkrétně s využitím balíčku nazvaného pexpect. Tentokrát se spustí interpret Pythonu, na jeho výzvu (prompt) se zadá příkaz pro otočení řetězce a z výstupu se zjistí výsledek této operace:
import pexpect c = pexpect.spawnu('/usr/bin/env python') c.expect('>>>') print('And now for something completely different...') print(''.join(reversed((c.before)))) print('Yes, it\'s python, but it\'s backwards.') print() print('Escape character is \'^]\'.') print(c.after, end=' ') c.interact() c.kill(1) print('is alive:', c.isalive())
3. Balíčky go-expect, gexpect a GoExpect
Jak jsme si již řekli v úvodní kapitole, existuje pro programovací jazyk Go hned několik knihoven, které ve větší či menší míře implementují základní operace, které známe z původního nástroje expect. Jedná se o následující knihovny:
- Balíček goexpect
https://github.com/google/goexpect - Balíček go-expect
https://github.com/Netflix/go-expect - Balíček gexpect
https://github.com/ThomasRooney/gexpect
V navazujících kapitolách se budeme zabývat především druhým zmíněným balíčkem pojmenovaným go-expect a balíčkem třetím gexpect. První balíček bude popsán v samostatném článku, protože se nabízí poměrně rozsáhlou funkcionalitu.
4. Nejjednodušší použití balíčku go-expect – test obsahu standardního výstupu vybrané aplikace
Prvním balíčkem s implementací vybraných operací nástroje expect v programovacím jazyce Go je balíček nazvaný go-expect. Ukažme si nyní jedno z nejjednodušších použití tohoto balíčku. Vytvoříme test, v němž spustíme příkaz uname (bez dalších parametrů) a následně otestujeme, zda se na standardním výstupu z tohoto nástroje objevil text „Linux“. Nejprve je nutné získat instanci virtuální konzole, pochopitelně s kontrolou, zda při její konstrukci nedošlo k chybě:
console, err := expect.NewConsole(expect.WithStdout(os.Stdout)) if err != nil { log.Fatal(err) } defer console.Close()
Dále se přes standardní knihovnu os/exec spustí příkaz „uname“ a upraví se jeho vstupně/výstupní proudy, aby příkaz bylo možné ovládat z virtuální konzole:
command := exec.Command("uname") command.Stdin = console.Tty() command.Stdout = console.Tty() command.Stderr = console.Tty() err = command.Start()
Na standardním výstupu aplikace by se měl objevit řetězec „Linux“, což ihned zjistíme:
console.ExpectString("Linux")
Úplný zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article43/go-expect/01_check_uname.go:
package main import ( "log" "os" "os/exec" "time" expect "github.com/Netflix/go-expect" ) func main() { console, err := expect.NewConsole(expect.WithStdout(os.Stdout)) if err != nil { log.Fatal(err) } defer console.Close() command := exec.Command("uname") command.Stdin = console.Tty() command.Stdout = console.Tty() command.Stderr = console.Tty() err = command.Start() if err != nil { log.Fatal(err) } time.Sleep(time.Second) console.ExpectString("Linux") err = command.Wait() if err != nil { log.Fatal(err) } }
Při spuštění aplikace (psané v Go) se na standardním výstupu postupně objevují i texty vypsané spuštěným nástrojem uname:
Linux
5. Nastavení doby čekání při testu standardního výstupu aplikace
V případě, že se na standardním výstupu spuštěné aplikace neobjeví očekávaný řetězec (v předchozím příkladu to byl text „Linux“), bude program ve výchozím nastavení pozastaven na neomezenou dobu, protože nemůže vědět, kdy (a zda vůbec) se tento řetězec může objevit. Toto chování většinou není ideální, protože se může stát, že se očekávaný řetězec neukáže nikdy. Z tohoto důvodu lze již při inicializaci konzole určit čas, po který se má po zavolání metody Expect na řetězec čekat:
console, err := expect.NewConsole(expect.WithStdout(os.Stdout), expect.WithDefaultTimeout(100*time.Millisecond))
Příklad nepatrně upravíme takovým způsobem, aby se očekával řetězec „BSD“ namísto „Linux“:
str, err := console.ExpectString("BSD") if err != nil { log.Fatalf("BSD expected, but got %s", str) }
Takový řetězec se na testovaném stroji nemůže objevit, proto dojde po spuštění aplikace k očekávané chybě:
Linux 2019/11/23 13:01:37 BSD expected, but got Linux exit status 1
Úplný kód druhého demonstračního příkladu najdeme na adrese https://github.com/tisnik/go-root/blob/master/article43/go-expect/02_check_uname_timeout.go:
package main import ( "log" "os" "os/exec" "time" expect "github.com/Netflix/go-expect" ) func main() { console, err := expect.NewConsole(expect.WithStdout(os.Stdout), expect.WithDefaultTimeout(100*time.Millisecond)) if err != nil { log.Fatal(err) } defer console.Close() command := exec.Command("uname") command.Stdin = console.Tty() command.Stdout = console.Tty() command.Stderr = console.Tty() err = command.Start() if err != nil { log.Fatal(err) } time.Sleep(time.Second) str, err := console.ExpectString("BSD") if err != nil { log.Fatalf("BSD expected, but got %s", str) } err = command.Wait() if err != nil { log.Fatal(err) } }
6. Podobný příklad s testem výstupu příkazu curl
Přesné chování metody console.ExpectString si ověříme na dalším demonstračním příkladu, v němž bude spuštěn příkaz curl a testovat budeme, zda odpověď obsahuje informaci o přesunu stránky na odlišnou adresu (301 Moved Permanently):
package main import ( "log" "os" "os/exec" "time" expect "github.com/Netflix/go-expect" ) func main() { console, err := expect.NewConsole(expect.WithStdout(os.Stdout)) if err != nil { log.Fatal(err) } defer console.Close() command := exec.Command("curl", "-X", "HEAD", "-v", "github.com") command.Stdin = console.Tty() command.Stdout = console.Tty() command.Stderr = console.Tty() err = command.Start() if err != nil { log.Fatal(err) } time.Sleep(time.Second) console.ExpectString("Location: https://github.com/") err = command.Wait() if err != nil { log.Fatal(err) } }
Po spuštění příkladu si povšimněte, že se vypíše pouze výstup až do očekávaného řetězce, ale další zprávy již nejsou ani vypsány ani zpracovány. Metoda console.ExpectString totiž prochází přečteným výstupem aplikace od aktuálního bodu až do toho okamžiku, kdy řetězec nalezne (pokud ho nenalezne, bude čekat na další výstup, popř. po určeném timeoutu skončí s chybou):
* Rebuilt URL to: github.com/ * Hostname was NOT found in DNS cache * Trying 140.82.118.4... * Connected to github.com (140.82.118.4) port 80 (#0) > HEAD / HTTP/1.1 > User-Agent: curl/7.35.0 > Host: github.com > Accept: */* > < HTTP/1.1 301 Moved Permanently < Content-length: 0 < Location: https://github.com/
7. Automatické ovládání aplikace díky koordinaci jejího standardního výstupu a vstupu
Největší přednost nástrojů typu expect spočívá v jejich schopnosti ovládat jinou aplikaci díky koordinaci jejího standardního výstupu (tisknutých zpráv, například otázek) a vstupu. Ukážeme si to na jednoduchém příkladu – přes telnet se přihlásíme do hry Zombie MUD (MUD=Multi-User Dungeon), počkáme na zobrazení hlavního menu a pokud se menu skutečně zobrazí, použijeme příkaz D (Disconnect). Naprosto stejným způsobem by ovšem bylo možné naskriptovat vytvoření nové postavy či dokonce projití několika patry podzemí:
package main import ( "log" "os" "os/exec" "time" expect "github.com/Netflix/go-expect" ) func main() { console, err := expect.NewConsole(expect.WithStdout(os.Stdout)) if err != nil { log.Fatal(err) } defer console.Close() command := exec.Command("telnet", "zombiemud.org") command.Stdin = console.Tty() command.Stdout = console.Tty() command.Stderr = console.Tty() err = command.Start() if err != nil { log.Fatal(err) } time.Sleep(time.Second) console.ExpectString("... online since 1994") console.ExpectString("Your choice or name:") console.Send("d\n") console.ExpectString("Ok, see you later!") err = command.Wait() if err != nil { log.Fatal(err) } }
Ukázka komunikace námi vytvořeného pomocného prográmku se hrou:
Trying 85.23.110.31... Connected to zombiemud.org. Escape character is '^]'. Welcome to ... ___ __ __) __ __) ______ (, ) /) , (, /| /| (, / / (, / ) / ______ (/_ _ / | / | / / / / _/_(_) // (_/_) _(__(/_) / |/ |_ / / _/___ /_ ) / (_/ ' (___(_ (_/___ / (__ / ... online since 1994. There are currently 45 mortals and 5 wizards online. Give me your name or choose one of the following: [C]reate a new character [W]ho is playing [V]isit the game [S]tatus of the game [D]isconnect Your choice or name: d Ok, see you later!
8. Programové ovládání interpretru jazyka Python
Podobným způsobem můžeme ovládat i interpretry různých programovacích jazyků. Další demonstrační příklad ukazuje ovládání interpretru Pythonu spouštěného příkazem python (na základě nastavení systému se tedy může jednat buď o Python 2 nebo o Python 3). Po spuštění interpretru očekáváme jeho výzvu (prompt), po jejímž objevení zadáme aritmetický výraz s očekáváním správného výsledku. Nakonec je interpret ukončen příkazem (přesněji řečeno funkcí) quit():
package main import ( "log" "os" "os/exec" "time" expect "github.com/Netflix/go-expect" ) func main() { console, err := expect.NewConsole(expect.WithStdout(os.Stdout)) if err != nil { log.Fatal(err) } defer console.Close() command := exec.Command("python") command.Stdin = console.Tty() command.Stdout = console.Tty() command.Stderr = console.Tty() err = command.Start() if err != nil { log.Fatal(err) } time.Sleep(time.Second) console.ExpectString(">>> ") console.SendLine("1+2") console.ExpectString("3") console.ExpectString(">>> ") console.SendLine("6*7") console.ExpectString("42") console.ExpectString(">>> ") console.SendLine("quit()") err = command.Wait() if err != nil { log.Fatal(err) } }
Ukázka dialogu mezi naším prográmkem a interpretrem Pythonu (schválně nastaveným na starší verzi):
Python 2.7.6 (default, Nov 23 2017, 15:49:48) [GCC 4.8.4] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> 1+2 3 >>> 6*7 42 >>>
9. Reakce na několik alternativních řetězců na výstupu aplikace
Poněkud komplikovanější situace nastane ve chvíli, kdy je nutné rozhodnout, který z řetězců se objevil na konzoli ovládané či testované aplikace. Máme dvě možnosti – buď použít regulární výrazy následované rozeskokem, nebo metodu console.ExpectString nahradit její obecnější variantou s více alternativními řetězci:
str, err := console.Expect(expect.String("Python 2", "Python 3"), expect.WithTimeout(100*time.Millisecond))
Následně je již možné zjistit, jaká situace nastala – zda se objevil alespoň jeden z řetězců či naopak řetězec žádný (což je chyba):
if err != nil { fmt.Println("Python not detected") log.Fatal(err) } if str == "Python 2" { console.SendLine("print 1,2,3") _, err = console.ExpectString("1 2 3") if err != nil { log.Fatal(err) } console.ExpectString(">>> ") } else { console.SendLine("print(1,2,3)") _, err = console.ExpectString("1 2 3") if err != nil { log.Fatal(err) } console.ExpectString(">>> ") }
Ukázka možného výstupu:
Python 2.7.6 (default, Nov 23 2017, 15:49:48) [GCC 4.8.4] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> print 1,2,3 1 2 3 >>>
Úplný zdrojový kód takto upraveného demonstračního příkladu vypadá následovně:
package main import ( "fmt" "log" "os" "os/exec" "time" expect "github.com/Netflix/go-expect" ) func main() { console, err := expect.NewConsole(expect.WithStdout(os.Stdout)) if err != nil { log.Fatal(err) } defer console.Close() command := exec.Command("python") command.Stdin = console.Tty() command.Stdout = console.Tty() command.Stderr = console.Tty() err = command.Start() if err != nil { log.Fatal(err) } time.Sleep(time.Second) str, err := console.Expect(expect.String("Python 2", "Python 3"), expect.WithTimeout(100*time.Millisecond)) if err != nil { fmt.Println("Python not detected") log.Fatal(err) } if str == "Python 2" { console.SendLine("print 1,2,3") _, err = console.ExpectString("1 2 3") if err != nil { log.Fatal(err) } console.ExpectString(">>> ") } else { console.SendLine("print(1,2,3)") _, err = console.ExpectString("1 2 3") if err != nil { log.Fatal(err) } console.ExpectString(">>> ") } console.SendLine("quit()") err = command.Wait() if err != nil { log.Fatal(err) } }
10. Testování aplikací s textovým rozhraním kombinací balíčků testing a go-expect
Nic nám nebrání použít knihovnu go-expect společně s knihovnou testing pro vytvoření testů funkcionality či integračních testů. Jedna z možností (pravda – poněkud umělá) je ukázána v dalším příkladu, v němž testujeme schopnost interpretru Pythonu vyhodnotit parametry příkazu print (Python 2) či funkce print (Python 3). Celý test je psán s využitím možností nabízených standardní knihovnou testing:
package main import ( "os" "os/exec" "testing" "time" expect "github.com/Netflix/go-expect" ) func TestPythonInterpreter(t *testing.T) { console, err := expect.NewConsole(expect.WithStdout(os.Stdout)) if err != nil { t.Fatal(err) } defer console.Close() t.Log("Console created") command := exec.Command("python") command.Stdin = console.Tty() command.Stdout = console.Tty() command.Stderr = console.Tty() err = command.Start() if err != nil { t.Fatal(err) } t.Log("Python interpreter started") time.Sleep(time.Second) str, err := console.Expect(expect.String("Python 2", "Python 3"), expect.WithTimeout(100*time.Millisecond)) if err != nil { t.Fatal("Python not detected") } t.Log("Python interpreter detected: " + str) if str == "Python 2" { console.SendLine("print 1,2,3") _, err = console.ExpectString("1 2 3") if err != nil { t.Fatal("print statement failure") } t.Log("print statement works as expected") _, err = console.ExpectString(">>> ") if err != nil { t.Fatal("prompt is not displayed") } } else { console.SendLine("print(1,2,3)") _, err = console.ExpectString("1 2 3") if err != nil { t.Fatal("print function failure") } t.Log("print function works as expected") _, err = console.ExpectString(">>> ") if err != nil { t.Fatal("prompt is not displayed") } } console.SendLine("quit()") err = command.Wait() if err != nil { t.Fatal(err) } t.Log("Done") }
Test musíme spustit příkazem go test -v jméno_souboru.go. Výstup může vypadat následovně:
=== RUN TestPythonInterpreter Python 2.7.6 (default, Nov 23 2017, 15:49:48) [GCC 4.8.4] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> print 1,2,3 1 2 3 >>> --- PASS: TestPythonInterpreter (1.01s) 07_python_test.go:18: Console created 07_python_test.go:30: Python interpreter started 07_python_test.go:37: Python interpreter detected: Python 2 07_python_test.go:45: print statement works as expected 07_python_test.go:69: Done PASS ok command-line-arguments 1.011s
11. Složitější příklad – test korektnosti výpočtů prováděných intepretrem Pythonu
Posledním příkladem, v němž využijeme knihovnu go-expect bude test korektnosti výpočtů s využitím operátoru ** v Pythonu. Tento operátor slouží pro výpočet funkce xy; pro jednoduchost otestujeme jeho funkcionalitu při výpočtu mocninné řady o základu 2 (1, 2, 4, 8, 16, …). Naivní, ovšem funkční implementace založená na použití knihoven testing a go-expect může vypadat následovně:
package main import ( "fmt" "os" "os/exec" "testing" "time" expect "github.com/Netflix/go-expect" ) func TestPythonInterpreter(t *testing.T) { console, err := expect.NewConsole(expect.WithStdout(os.Stdout)) if err != nil { t.Fatal(err) } defer console.Close() t.Log("Console created") command := exec.Command("python") command.Stdin = console.Tty() command.Stdout = console.Tty() command.Stderr = console.Tty() err = command.Start() if err != nil { t.Fatal(err) } t.Log("Python interpreter started") time.Sleep(time.Second) str, err := console.Expect(expect.String("Python 2", "Python 3"), expect.WithTimeout(100*time.Millisecond)) if err != nil { t.Fatal("Python not detected") } t.Log("Python interpreter detected: " + str) for i := uint(1); i < 10; i++ { console.SendLine(fmt.Sprintf("2**%d", i)) _, err = console.Expectf("%d", 1<<i) if err != nil { t.Fatal("Math is wrong!") } t.Logf("Math is ok for input %d", i) } console.SendLine("quit()") err = command.Wait() if err != nil { t.Fatal(err) } t.Log("Done") }
Tento test spustíme příkazem:
$ go test -v 08_python_math_test.go
S následujícími výsledky (platí pro výchozí interpret Pythonu na testovacím počítači):
=== RUN TestPythonInterpreter Python 2.7.6 (default, Nov 23 2017, 15:49:48) [GCC 4.8.4] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> 2**1 2**2 2 >>> 2**2 4 >>> 2**3 8 >>> 2**4 16 >>> 2**5 32 >>> 2**6 64 >>> 2**7 128 >>> 2**8 256 >>> 2**9 512 --- PASS: TestPythonInterpreter (1.01s) 08_python_math_test.go:19: Console created 08_python_math_test.go:31: Python interpreter started 08_python_math_test.go:38: Python interpreter detected: Python 2 08_python_math_test.go:46: Math is ok for input 1 08_python_math_test.go:46: Math is ok for input 2 08_python_math_test.go:46: Math is ok for input 3 08_python_math_test.go:46: Math is ok for input 4 08_python_math_test.go:46: Math is ok for input 5 08_python_math_test.go:46: Math is ok for input 6 08_python_math_test.go:46: Math is ok for input 7 08_python_math_test.go:46: Math is ok for input 8 08_python_math_test.go:46: Math is ok for input 9 08_python_math_test.go:55: Done PASS ok command-line-arguments 1.013s
12. Balíček gexpect
Druhým balíčkem, s nímž se dnes ve stručnosti seznámíme, je balíček nazvaný gexpect. Jeho použití je ve skutečnosti pro jednodušší případy mnohem snadnější, než tomu bylo u balíčku go-expect. Ostatně se podívejme na to, jak lze přepsat příklad spouštějící nástroj uname a testující jeho výsledek:
package main import ( "log" "github.com/ThomasRooney/gexpect" ) func main() { child, err := gexpect.Spawn("uname") if err != nil { log.Fatal(err) } err = child.Expect("Linux") if err != nil { log.Fatal(err) } child.Wait() }
Druhý příklad (se jménem „BSD“ namísto „Linux“) ukazuje, jak se knihovna gexpect chová ve chvíli, kdy nenalezne očekávaný řetězec:
package main import ( "log" "github.com/ThomasRooney/gexpect" ) func main() { child, err := gexpect.Spawn("uname") if err != nil { log.Fatal(err) } err = child.Expect("BSD") if err != nil { log.Fatal(err) } child.Wait() }
Výsledek ukazuje (mj.), že se testovaný příkaz ukončil dřív, než byl očekávaný řetězec nalezen:
2019/11/23 19:05:46 read /dev/ptmx: input/output error exit status 1
13. Přepis příkladu volajícího příkaz curl
Jen pro úplnost si ukažme i přepis demonstračního příkladu ze šesté kapitoly:
package main import ( "log" "github.com/ThomasRooney/gexpect" ) func main() { child, err := gexpect.Spawn("curl -X HEAD -v github.com") if err != nil { log.Fatal(err) } err = child.Expect("Location: https://github.com/") if err != nil { log.Fatal(err) } child.Wait() }
14. Ovládání interaktivní hry spuštěné přes telnet
Hru Zombie MUD, s jejíž existencí jsme se již seznámili v sedmé kapitole, můžeme spustit (resp. přesněji řečeno připojit se k ní) a ovládat s využitím knihovny goexpect relativně snadno. Prozatím si uvedeme variantu, v níž se neustále opakují testy úspěšnosti jednotlivých příkazů:
package main import ( "log" "github.com/ThomasRooney/gexpect" ) func main() { child, err := gexpect.Spawn("telnet zombiemud.org") if err != nil { log.Fatal(err) } err = child.Expect("... online since 1994") if err != nil { log.Fatal(err) } err = child.Expect("Your choice or name:") if err != nil { log.Fatal(err) } child.Send("d\n") err = child.Expect("Ok, see you later!") if err != nil { log.Fatal(err) } child.Wait() }
Namísto příkazu:
child.Send("d\n")
je výhodnější použít příkaz:
child.SendLine("d")
Takže výše uvedený příklad můžeme nepatrně upravit a vylepšit:
package main import ( "log" "github.com/ThomasRooney/gexpect" ) func main() { child, err := gexpect.Spawn("telnet zombiemud.org") if err != nil { log.Fatal(err) } err = child.Expect("... online since 1994") if err != nil { log.Fatal(err) } err = child.Expect("Your choice or name:") if err != nil { log.Fatal(err) } child.SendLine("d") err = child.Expect("Ok, see you later!") if err != nil { log.Fatal(err) } child.Wait() }
15. Ovládání interpretru Pythonu
Pro ovládání interpretru Pythonu si připravíme několik pomocných funkcí, které nám zjednoduší vlastní zápis „skriptu“. Bude se jednat o funkci pro poslání příkazu (ukončeného Enterem) s kontrolou, zda se poslání podařilo:
func sendCommand(child *gexpect.ExpectSubprocess, command string) { err := child.SendLine(command) if err != nil { log.Fatal(err) } }
A dále o dvojici funkcí, které očekávají obecný výstup produkovaný interpretrem, popř. konkrétně výzvu (prompt):
func expectOutput(child *gexpect.ExpectSubprocess, output string) { err := child.Expect(output) if err != nil { log.Fatal(err) } } func expectPrompt(child *gexpect.ExpectSubprocess) { expectOutput(child, ">>> ") }
Samotný „skript“, který do interpretru vloží dvojici aritmetických výrazů a bude očekávat a testovat jejich výsledek, se tak zkrátí (včetně příkazu pro ukončení interpretru):
expectPrompt(child) sendCommand(child, "1+2") expectOutput(child, "3") expectPrompt(child) sendCommand(child, "6*7") expectOutput(child, "42") expectPrompt(child) sendCommand(child, "quit()")
Podívejme se nyní na úplný zdrojový kód takto upraveného příkladu. Je přehlednější, než tomu bylo v případě použití knihovny go-expect:
package main import ( "log" "github.com/ThomasRooney/gexpect" ) func expectOutput(child *gexpect.ExpectSubprocess, output string) { err := child.Expect(output) if err != nil { log.Fatal(err) } } func expectPrompt(child *gexpect.ExpectSubprocess) { expectOutput(child, ">>> ") } func sendCommand(child *gexpect.ExpectSubprocess, command string) { err := child.SendLine(command) if err != nil { log.Fatal(err) } } func main() { child, err := gexpect.Spawn("python") if err != nil { log.Fatal(err) } expectPrompt(child) sendCommand(child, "1+2") expectOutput(child, "3") expectPrompt(child) sendCommand(child, "6*7") expectOutput(child, "42") expectPrompt(child) sendCommand(child, "quit()") child.Wait() }
16. Detekce, který interpret Pythonu byl spuštěn
V předchozím textu jsme se seznámili s tím, jakým způsobem je možné s využitím knihovny go-expect zjistit, který interpret Pythonu je spuštěn. V knihovně gexpect k tomuto účelu použijeme regulární výraz:
strs, err := child.ExpectRegexFind("Python [23]") if err != nil { log.Fatal(err) }
Pokud se nevrátí chyba, bude proměnná strs obsahovat všechny řetězce odpovídající uvedenému regulárnímu výrazu, které byly na standardním výstupu aplikace detekovány. Nás bude zajímat první (a jediný!) výskyt, tedy například:
if strs[0] == "Python 2" { log.Println("Python 2") ... ... ... } else { log.Println("Python 3") ... ... ... }
Příklad použití této konstrukce při testování příkazu print (Python 2) nebo funkce print() (Python 3):
package main import ( "log" "time" "github.com/ThomasRooney/gexpect" ) func expectOutput(child *gexpect.ExpectSubprocess, output string) { err := child.ExpectTimeout(output, time.Second) if err != nil { log.Fatal(err) } } func expectPrompt(child *gexpect.ExpectSubprocess) { expectOutput(child, ">>> ") } func sendCommand(child *gexpect.ExpectSubprocess, command string) { err := child.SendLine(command) if err != nil { log.Fatal(err) } } func main() { child, err := gexpect.Spawn("python") if err != nil { log.Fatal(err) } strs, err := child.ExpectRegexFind("Python [23]") if err != nil { log.Fatal(err) } if strs[0] == "Python 2" { log.Println("Python 2") expectPrompt(child) sendCommand(child, "print 1,2,3") expectOutput(child, "1 2 3") } else { log.Println("Python 3") expectPrompt(child) sendCommand(child, "print(1,2,3)") expectOutput(child, "1 2 3") } expectPrompt(child) sendCommand(child, "quit()") child.Wait() }
17. Kombinace knihoven testing a gexpect
Pochopitelně nám nic nebrání využít knihovnu testing společně s knihovnou gexpect. Předchozí příklad lze přepsat do formy jednotkových testů následovně:
package main import ( "testing" "time" "github.com/ThomasRooney/gexpect" ) func expectOutput(t *testing.T, child *gexpect.ExpectSubprocess, output string) { err := child.ExpectTimeout(output, time.Second) if err != nil { t.Fatal(err) } } func expectPrompt(t *testing.T, child *gexpect.ExpectSubprocess) { expectOutput(t, child, ">>> ") } func sendCommand(t *testing.T, child *gexpect.ExpectSubprocess, command string) { err := child.SendLine(command) if err != nil { t.Fatal(err) } } func TestPythonInterpreter(t *testing.T) { child, err := gexpect.Spawn("python") if err != nil { t.Fatal(err) } strs, err := child.ExpectRegexFind("Python [23]") if err != nil { t.Fatal(err) } if strs[0] == "Python 2" { t.Log("Python 2") expectPrompt(t, child) sendCommand(t, child, "print 1,2,3") expectOutput(t, child, "1 2 3") } else { t.Log("Python 3") expectPrompt(t, child) sendCommand(t, child, "print(1,2,3)") expectOutput(t, child, "1 2 3") } expectPrompt(t, child) sendCommand(t, child, "quit()") child.Wait() }
Pro spuštění takto naprogramovaných testů je nutné použít příkaz go test -v a nikoli go run:
=== RUN TestPythonInterpreter --- PASS: TestPythonInterpreter (0.03s) 08_python_test.go:40: Python 2 PASS ok command-line-arguments 0.032s
18. Test korektnosti výpočtů prováděných intepretrem Pythonu podruhé
V jedenácté kapitole jsme se seznámili s utilitou (jednalo se o test) sloužící pro zjištění, zda v interpretru Pythonu pracuje správně aritmetický operátor **. Tento test můžeme přepsat takovým způsobem, aby se v něm použila jak standardní knihovna testing, tak i knihovna gexpect:
package main import ( "fmt" "testing" "time" "github.com/ThomasRooney/gexpect" ) func expectOutput(t *testing.T, child *gexpect.ExpectSubprocess, output string) { err := child.ExpectTimeout(output, time.Second) if err != nil { t.Fatal(err) } } func expectPrompt(t *testing.T, child *gexpect.ExpectSubprocess) { expectOutput(t, child, ">>> ") } func sendCommand(t *testing.T, child *gexpect.ExpectSubprocess, command string) { err := child.SendLine(command) if err != nil { t.Fatal(err) } } func TestPythonInterpreter(t *testing.T) { child, err := gexpect.Spawn("python") if err != nil { t.Fatal(err) } t.Log("Python interpreter started") strs, err := child.ExpectRegexFind("Python [23]") if err != nil { t.Fatal("Python not detected") } t.Log("Python interpreter detected: " + strs[0]) for i := uint(1); i < 10; i++ { sendCommand(t, child, fmt.Sprintf("2**%d", i)) expectOutput(t, child, fmt.Sprintf("%d", 1<<i)) t.Logf("Math is ok for input %d", i) } expectPrompt(t, child) sendCommand(t, child, "quit()") child.Wait() }
Po spuštění výše uvedeného demonstračního příkladu příkazem go test -v by se měly objevit zprávy oznamující, že test funkcionality operátoru ** proběhl v pořádku:
=== RUN TestPythonInterpreter --- PASS: TestPythonInterpreter (0.03s) 09_python_math_test.go:34: Python interpreter started 09_python_math_test.go:40: Python interpreter detected: Python 2 09_python_math_test.go:45: Math is ok for input 1 09_python_math_test.go:45: Math is ok for input 2 09_python_math_test.go:45: Math is ok for input 3 09_python_math_test.go:45: Math is ok for input 4 09_python_math_test.go:45: Math is ok for input 5 09_python_math_test.go:45: Math is ok for input 6 09_python_math_test.go:45: Math is ok for input 7 09_python_math_test.go:45: Math is ok for input 8 09_python_math_test.go:45: Math is ok for input 9 PASS ok command-line-arguments 0.035s
19. Repositář s demonstračními příklady
Zdrojové kódy všech dnes použitých demonstračních příkladů byly uloženy do Git repositáře, který je dostupný na adrese https://github.com/tisnik/go-root (stále na GitHubu :-). V případě, že nebudete chtít klonovat celý repositář (ten je ovšem – alespoň prozatím – velmi malý, dnes má přibližně pět megabajtů), můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:
20. Odkazy na Internetu
- Balíček goexpect
https://github.com/google/goexpect - Balíček go-expect
https://github.com/Netflix/go-expect - Balíček gexpect
https://github.com/ThomasRooney/gexpect - Expect (originál naprogramovaný v TCL)
https://core.tcl-lang.org/expect/index - Expect (Wikipedia)
https://en.wikipedia.org/wiki/Expect - Pexpect
https://pexpect.readthedocs.io/en/stable/ - Golang SSH Client: Multiple Commands, Crypto & Goexpect Examples
http://networkbit.ch/golang-ssh-client/ - goblin na GitHubu
https://github.com/franela/goblin - Mocha framework
https://mochajs.org/ - frisby na GitHubu
https://github.com/verdverm/frisby - package frisby
https://godoc.org/github.com/verdverm/frisby - Frisby alternatives and similar packages (generováno)
https://go.libhunt.com/frisby-alternatives - Cucumber for golang
https://github.com/DATA-DOG/godog - How to Use Godog for Behavior-driven Development in Go
https://semaphoreci.com/community/tutorials/how-to-use-godog-for-behavior-driven-development-in-go - Comparative Analysis Of GoLang Testing Frameworks
https://www.slideshare.net/DushyantBhalgami/comparative-analysis-of-golang-testing-frameworks - A Quick Guide to Testing in Golang
https://caitiem.com/2016/08/18/a-quick-guide-to-testing-in-golang/ - Tom's Obvious, Minimal Language.
https://github.com/toml-lang/toml - xml.org
http://www.xml.org/ - Soubory .properties
https://en.wikipedia.org/wiki/.properties - Soubory INI
https://en.wikipedia.org/wiki/INI_file - JSON to YAML
https://www.json2yaml.com/ - Data Format Converter
https://toolkit.site/format.html - Viper na GitHubu
https://github.com/spf13/viper - GoDotEnv na GitHubu
https://github.com/joho/godotenv - The fantastic ORM library for Golang
http://gorm.io/ - Dokumentace k balíčku gorilla/mux
https://godoc.org/github.com/gorilla/mux - Gorilla web toolkitk
http://www.gorillatoolkit.org/ - Metric types
https://prometheus.io/docs/concepts/metric_types/ - Histograms with Prometheus: A Tale of Woe
http://linuxczar.net/blog/2017/06/15/prometheus-histogram-2/ - Why are Prometheus histograms cumulative?
https://www.robustperception.io/why-are-prometheus-histograms-cumulative - Histograms and summaries
https://prometheus.io/docs/practices/histograms/ - Instrumenting Golang server in 5 min
https://medium.com/@gsisimogang/instrumenting-golang-server-in-5-min-c1c32489add3 - Semantic Import Versioning in Go
https://www.aaronzhuo.com/semantic-import-versioning-in-go/ - Sémantické verzování
https://semver.org/ - Getting started with Go modules
https://medium.com/@fonseka.live/getting-started-with-go-modules-b3dac652066d - Create projects independent of $GOPATH using Go Modules
https://medium.com/mindorks/create-projects-independent-of-gopath-using-go-modules-802260cdfb51o - Anatomy of Modules in Go
https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16 - Modules
https://github.com/golang/go/wiki/Modules - Go Modules Tutorial
https://tutorialedge.net/golang/go-modules-tutorial/ - Module support
https://golang.org/cmd/go/#hdr-Module_support - Go Lang: Memory Management and Garbage Collection
https://vikash1976.wordpress.com/2017/03/26/go-lang-memory-management-and-garbage-collection/ - Golang Internals, Part 4: Object Files and Function Metadata
https://blog.altoros.com/golang-part-4-object-files-and-function-metadata.html - What is REPL?
https://pythonprogramminglanguage.com/repl/ - What is a REPL?
https://codewith.mu/en/tutorials/1.0/repl - Programming at the REPL: Introduction
https://clojure.org/guides/repl/introduction - What is REPL? (Quora)
https://www.quora.com/What-is-REPL - Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/ - Read-eval-print loop (Wikipedia)
https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop - Vim as a Go (Golang) IDE using LSP and vim-go
https://octetz.com/posts/vim-as-go-ide - gopls
https://github.com/golang/go/wiki/gopls - IDE Integration Guide
https://github.com/stamblerre/gocode/blob/master/docs/IDE_integration.md - How to instrument Go code with custom expvar metrics
https://sysdig.com/blog/golang-expvar-custom-metrics/ - Golang expvar metricset (Metricbeat Reference)
https://www.elastic.co/guide/en/beats/metricbeat/7.x/metricbeat-metricset-golang-expvar.html - Package expvar
https://golang.org/pkg/expvar/#NewInt - Java Platform Debugger Architecture: Overview
https://docs.oracle.com/en/java/javase/11/docs/specs/jpda/jpda.html - The JVM Tool Interface (JVM TI): How VM Agents Work
https://www.oracle.com/technetwork/articles/javase/index-140680.html - JVM Tool Interface Version 11.0
https://docs.oracle.com/en/java/javase/11/docs/specs/jvmti.html - Creating a Debugging and Profiling Agent with JVMTI
http://www.oracle.com/technetwork/articles/javase/jvmti-136367.html - JVM TI (Wikipedia)
http://en.wikipedia.org/wiki/JVM_TI - IBM JVMTI extensions
http://publib.boulder.ibm.com/infocenter/realtime/v2r0/index.jsp?topic=%2Fcom.ibm.softrt.doc%2Fdiag%2Ftools%2Fjvmti_extensions.html - Go & cgo: integrating existing C code with Go
http://akrennmair.github.io/golang-cgo-slides/#1 - Using cgo to call C code from within Go code
https://wenzr.wordpress.com/2018/06/07/using-cgo-to-call-c-code-from-within-go-code/ - Package trace
https://golang.org/pkg/runtime/trace/ - Introducing HTTP Tracing
https://blog.golang.org/http-tracing - Command trace
https://golang.org/cmd/trace/ - A StreamLike, Immutable, Lazy Loading and smart Golang Library to deal with slices
https://github.com/wesovilabs/koazee - Funkce vyššího řádu v knihovně Underscore
https://www.root.cz/clanky/funkce-vyssiho-radu-v-knihovne-underscore/ - Delve: a debugger for the Go programming language.
https://github.com/go-delve/delve - Příkazy debuggeru Delve
https://github.com/go-delve/delve/tree/master/Documentation/cli - Debuggery a jejich nadstavby v Linuxu
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu/ - Debuggery a jejich nadstavby v Linuxu (2. část)
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-2-cast/ - Debuggery a jejich nadstavby v Linuxu (3): Nemiver
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-3-nemiver/ - Debuggery a jejich nadstavby v Linuxu (4): KDbg
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-4-kdbg/ - Debuggery a jejich nadstavby v Linuxu (5): ladění aplikací v editorech Emacs a Vim
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-5-ladeni-aplikaci-v-editorech-emacs-a-vim/ - Debugging Go Code with GDB
https://golang.org/doc/gdb - Debugging Go (golang) programs with gdb
https://thornydev.blogspot.com/2014/01/debugging-go-golang-programs-with-gdb.html - GDB – Dokumentace
http://sourceware.org/gdb/current/onlinedocs/gdb/ - GDB – Supported Languages
http://sourceware.org/gdb/current/onlinedocs/gdb/Supported-Languages.html#Supported-Languages - GNU Debugger (Wikipedia)
https://en.wikipedia.org/wiki/GNU_Debugger - The LLDB Debugger
http://lldb.llvm.org/ - Debugger (Wikipedia)
https://en.wikipedia.org/wiki/Debugger - 13 Linux Debuggers for C++ Reviewed
http://www.drdobbs.com/testing/13-linux-debuggers-for-c-reviewed/240156817 - Go is on a Trajectory to Become the Next Enterprise Programming Language
https://hackernoon.com/go-is-on-a-trajectory-to-become-the-next-enterprise-programming-language-3b75d70544e - Go Proverbs: Simple, Poetic, Pithy
https://go-proverbs.github.io/ - Handling Sparse Files on Linux
https://www.systutorials.com/136652/handling-sparse-files-on-linux/ - Gzip (Wikipedia)
https://en.wikipedia.org/wiki/Gzip - Deflate
https://en.wikipedia.org/wiki/DEFLATE - 10 tools written in Go that every developer needs to know
https://gustavohenrique.net/en/2019/01/10-tools-written-in-go-that-every-dev-needs-to-know/ - Hexadecimální prohlížeče a editory s textovým uživatelským rozhraním
https://www.root.cz/clanky/hexadecimalni-prohlizece-a-editory-s-textovym-uzivatelskym-rozhranim/ - Hex dump
https://en.wikipedia.org/wiki/Hex_dump - Rozhraní io.ByteReader
https://golang.org/pkg/io/#ByteReader - Rozhraní io.RuneReader
https://golang.org/pkg/io/#RuneReader - Rozhraní io.ByteScanner
https://golang.org/pkg/io/#ByteScanner - Rozhraní io.RuneScanner
https://golang.org/pkg/io/#RuneScanner - Rozhraní io.Closer
https://golang.org/pkg/io/#Closer - Rozhraní io.Reader
https://golang.org/pkg/io/#Reader - Rozhraní io.Writer
https://golang.org/pkg/io/#Writer - Typ Strings.Reader
https://golang.org/pkg/strings/#Reader - VACUUM (SQL)
https://www.sqlite.org/lang_vacuum.html - VACUUM (Postgres)
https://www.postgresql.org/docs/8.4/sql-vacuum.html - go-cron
https://github.com/rk/go-cron - gocron
https://github.com/jasonlvhit/gocron - clockwork
https://github.com/whiteShtef/clockwork - clockwerk
https://github.com/onatm/clockwerk - JobRunner
https://github.com/bamzi/jobrunner - Rethinking Cron
https://adam.herokuapp.com/past/2010/4/13/rethinking_cron/ - In the Beginning was the Command Line
https://web.archive.org/web/20180218045352/http://www.cryptonomicon.com/beginning.html - repl.it (REPL pro různé jazyky)
https://repl.it/languages - GOCUI – Go Console User Interface (celé uživatelské prostředí, nejenom input box)
https://github.com/jroimartin/gocui - Read–eval–print loop
https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop - go-prompt
https://github.com/c-bata/go-prompt - readline
https://github.com/chzyer/readline - A pure golang implementation for GNU-Readline kind library
https://golangexample.com/a-pure-golang-implementation-for-gnu-readline-kind-library/ - go-readline
https://github.com/fiorix/go-readline - 4 Python libraries for building great command-line user interfaces
https://opensource.com/article/17/5/4-practical-python-libraries - prompt_toolkit 2.0.3 na PyPi
https://pypi.org/project/prompt_toolkit/ - python-prompt-toolkit na GitHubu
https://github.com/jonathanslenders/python-prompt-toolkit - The GNU Readline Library
https://tiswww.case.edu/php/chet/readline/rltop.html - GNU Readline (Wikipedia)
https://en.wikipedia.org/wiki/GNU_Readline - readline — GNU readline interface (Python 3.x)
https://docs.python.org/3/library/readline.html - readline — GNU readline interface (Python 2.x)
https://docs.python.org/2/library/readline.html - GNU Readline Library – command line editing
https://tiswww.cwru.edu/php/chet/readline/readline.html - gnureadline 6.3.8 na PyPi
https://pypi.org/project/gnureadline/ - Editline Library (libedit)
http://thrysoee.dk/editline/ - Comparing Python Command-Line Parsing Libraries – Argparse, Docopt, and Click
https://realpython.com/comparing-python-command-line-parsing-libraries-argparse-docopt-click/ - libedit or editline
http://www.cs.utah.edu/~bigler/code/libedit.html - WinEditLine
http://mingweditline.sourceforge.net/ - rlcompleter — Completion function for GNU readline
https://docs.python.org/3/library/rlcompleter.html - rlwrap na GitHubu
https://github.com/hanslub42/rlwrap - rlwrap(1) – Linux man page
https://linux.die.net/man/1/rlwrap - readline(3) – Linux man page
https://linux.die.net/man/3/readline - history(3) – Linux man page
https://linux.die.net/man/3/history - Dokumentace k balíčku oglematchers
https://godoc.org/github.com/jacobsa/oglematchers - Balíček oglematchers
https://github.com/jacobsa/oglematchers - Dokumentace k balíčku ogletest
https://godoc.org/github.com/jacobsa/ogletest - Balíček ogletest
https://github.com/jacobsa/ogletest - Dokumentace k balíčku assert
https://godoc.org/github.com/stretchr/testify/assert - Testify – Thou Shalt Write Tests
https://github.com/stretchr/testify/ - package testing
https://golang.org/pkg/testing/ - Golang basics – writing unit tests
https://blog.alexellis.io/golang-writing-unit-tests/ - An Introduction to Programming in Go / Testing
https://www.golang-book.com/books/intro/12 - An Introduction to Testing in Go
https://tutorialedge.net/golang/intro-testing-in-go/ - Advanced Go Testing Tutorial
https://tutorialedge.net/golang/advanced-go-testing-tutorial/ - GoConvey
http://goconvey.co/ - Testing Techniques
https://talks.golang.org/2014/testing.slide - 5 simple tips and tricks for writing unit tests in #golang
https://medium.com/@matryer/5-simple-tips-and-tricks-for-writing-unit-tests-in-golang-619653f90742 - Afinní transformace
https://cs.wikibooks.org/wiki/Geometrie/Afinn%C3%AD_transformace_sou%C5%99adnic - package gg
https://godoc.org/github.com/fogleman/gg - Generate an animated GIF with Golang
http://tech.nitoyon.com/en/blog/2016/01/07/go-animated-gif-gen/ - Generate an image programmatically with Golang
http://tech.nitoyon.com/en/blog/2015/12/31/go-image-gen/ - The Go image package
https://blog.golang.org/go-image-package - Balíček draw2D: 2D rendering for different output (raster, pdf, svg)
https://github.com/llgcode/draw2d - Draw a rectangle in Golang?
https://stackoverflow.com/questions/28992396/draw-a-rectangle-in-golang - YAML
https://yaml.org/ - edn
https://github.com/edn-format/edn - Smile
https://github.com/FasterXML/smile-format-specification - Protocol-Buffers
https://developers.google.com/protocol-buffers/ - Marshalling (computer science)
https://en.wikipedia.org/wiki/Marshalling_(computer_science) - Unmarshalling
https://en.wikipedia.org/wiki/Unmarshalling - Introducing JSON
http://json.org/ - Package json
https://golang.org/pkg/encoding/json/ - The Go Blog: JSON and Go
https://blog.golang.org/json-and-go - Go by Example: JSON
https://gobyexample.com/json - Writing Web Applications
https://golang.org/doc/articles/wiki/ - Golang Web Apps
https://www.reinbach.com/blog/golang-webapps-1/ - Build web application with Golang
https://legacy.gitbook.com/book/astaxie/build-web-application-with-golang/details - Golang Templates – Golang Web Pages
https://www.youtube.com/watch?v=TkNIETmF-RU - Simple Golang HTTPS/TLS Examples
https://github.com/denji/golang-tls - Playing with images in HTTP response in golang
https://www.sanarias.com/blog/1214PlayingwithimagesinHTTPresponseingolang - MIME Types List
https://www.freeformatter.com/mime-types-list.html - Go Mutex Tutorial
https://tutorialedge.net/golang/go-mutex-tutorial/ - Creating A Simple Web Server With Golang
https://tutorialedge.net/golang/creating-simple-web-server-with-golang/ - Building a Web Server in Go
https://thenewstack.io/building-a-web-server-in-go/ - How big is the pipe buffer?
https://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer - How to turn off buffering of stdout in C
https://stackoverflow.com/questions/7876660/how-to-turn-off-buffering-of-stdout-in-c - setbuf(3) – Linux man page
https://linux.die.net/man/3/setbuf - setvbuf(3) – Linux man page (stejný obsah jako předchozí stránka)
https://linux.die.net/man/3/setvbuf - Select waits on a group of channels
https://yourbasic.org/golang/select-explained/ - Rob Pike: Simplicity is Complicated (video)
http://www.golang.to/posts/dotgo-2015-rob-pike-simplicity-is-complicated-youtube-16893 - Algorithms to Go
https://yourbasic.org/ - Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů
https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu/ - Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů: vlastní filtry a lexery
https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu-vlastni-filtry-a-lexery/ - Go Defer Simplified with Practical Visuals
https://blog.learngoprogramming.com/golang-defer-simplified-77d3b2b817ff - 5 More Gotchas of Defer in Go — Part II
https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-ii-cc550f6ad9aa - The Go Blog: Defer, Panic, and Recover
https://blog.golang.org/defer-panic-and-recover - The defer keyword in Swift 2: try/finally done right
https://www.hackingwithswift.com/new-syntax-swift-2-defer - Swift Defer Statement
https://andybargh.com/swift-defer-statement/ - Modulo operation (Wikipedia)
https://en.wikipedia.org/wiki/Modulo_operation - Node.js vs Golang: Battle of the Next-Gen Languages
https://www.hostingadvice.com/blog/nodejs-vs-golang/ - The Go Programming Language (home page)
https://golang.org/ - GoDoc
https://godoc.org/ - Go (programming language), Wikipedia
https://en.wikipedia.org/wiki/Go_(programming_language) - Go Books (kniha o jazyku Go)
https://github.com/dariubs/GoBooks - The Go Programming Language Specification
https://golang.org/ref/spec - Go: the Good, the Bad and the Ugly
https://bluxte.net/musings/2018/04/10/go-good-bad-ugly/ - Package builtin
https://golang.org/pkg/builtin/ - Package fmt
https://golang.org/pkg/fmt/ - The Little Go Book (další kniha)
https://github.com/dariubs/GoBooks - The Go Programming Language by Brian W. Kernighan, Alan A. A. Donovan
https://www.safaribooksonline.com/library/view/the-go-programming/9780134190570/ebook_split010.html - Learning Go
https://www.miek.nl/go/ - Go Bootcamp
http://www.golangbootcamp.com/ - Programming in Go: Creating Applications for the 21st Century (další kniha o jazyku Go)
http://www.informit.com/store/programming-in-go-creating-applications-for-the-21st-9780321774637 - Introducing Go (Build Reliable, Scalable Programs)
http://shop.oreilly.com/product/0636920046516.do - Learning Go Programming
https://www.packtpub.com/application-development/learning-go-programming - The Go Blog
https://blog.golang.org/ - Getting to Go: The Journey of Go's Garbage Collector
https://blog.golang.org/ismmkeynote - Go (programovací jazyk, Wikipedia)
https://cs.wikipedia.org/wiki/Go_(programovac%C3%AD_jazyk) - Rychle, rychleji až úplně nejrychleji s jazykem Go
https://www.root.cz/clanky/rychle-rychleji-az-uplne-nejrychleji-s-jazykem-go/ - Installing Go on the Raspberry Pi
https://dave.cheney.net/2012/09/25/installing-go-on-the-raspberry-pi - How the Go runtime implements maps efficiently (without generics)
https://dave.cheney.net/2018/05/29/how-the-go-runtime-implements-maps-efficiently-without-generics - Niečo málo o Go – Golang (slovensky)
http://golangsk.logdown.com/ - How Many Go Developers Are There?
https://research.swtch.com/gophercount - Most Popular Technologies (Stack Overflow Survery 2018)
https://insights.stackoverflow.com/survey/2018/#most-popular-technologies - Most Popular Technologies (Stack Overflow Survery 2017)
https://insights.stackoverflow.com/survey/2017#technology - JavaScript vs. Golang for IoT: Is Gopher Winning?
https://www.iotforall.com/javascript-vs-golang-iot/ - The Go Programming Language: Release History
https://golang.org/doc/devel/release.html - Go 1.11 Release Notes
https://golang.org/doc/go1.11 - Go 1.10 Release Notes
https://golang.org/doc/go1.10 - Go 1.9 Release Notes (tato verze je stále používána)
https://golang.org/doc/go1.9 - Go 1.8 Release Notes (i tato verze je stále používána)
https://golang.org/doc/go1.8 - Go on Fedora
https://developer.fedoraproject.org/tech/languages/go/go-installation.html - Writing Go programs
https://developer.fedoraproject.org/tech/languages/go/go-programs.html - The GOPATH environment variable
https://tip.golang.org/doc/code.html#GOPATH - Command gofmt
https://tip.golang.org/cmd/gofmt/ - The Go Blog: go fmt your code
https://blog.golang.org/go-fmt-your-code - C? Go? Cgo!
https://blog.golang.org/c-go-cgo - Spaces vs. Tabs: A 20-Year Debate Reignited by Google’s Golang
https://thenewstack.io/spaces-vs-tabs-a-20-year-debate-and-now-this-what-the-hell-is-wrong-with-go/ - 400,000 GitHub repositories, 1 billion files, 14 terabytes of code: Spaces or Tabs?
https://medium.com/@hoffa/400–000-github-repositories-1-billion-files-14-terabytes-of-code-spaces-or-tabs-7cfe0b5dd7fd - Gofmt No Longer Allows Spaces. Tabs Only
https://news.ycombinator.com/item?id=7914523 - Why does Go „go fmt“ uses tabs instead of whitespaces?
https://www.quora.com/Why-does-Go-go-fmt-uses-tabs-instead-of-whitespaces - Interactive: The Top Programming Languages 2018
https://spectrum.ieee.org/static/interactive-the-top-programming-languages-2018 - Go vs. Python
https://www.peterbe.com/plog/govspy - PackageManagementTools
https://github.com/golang/go/wiki/PackageManagementTools - A Tour of Go: Type inference
https://tour.golang.org/basics/14 - Go Slices: usage and internals
https://blog.golang.org/go-slices-usage-and-internals - Go by Example: Slices
https://gobyexample.com/slices - What is the point of slice type in Go?
https://stackoverflow.com/questions/2098874/what-is-the-point-of-slice-type-in-go - The curious case of Golang array and slices
https://medium.com/@hackintoshrao/the-curious-case-of-golang-array-and-slices-2565491d4335 - Introduction to Slices in Golang
https://www.callicoder.com/golang-slices/ - Golang: Understanding ‚null‘ and nil
https://newfivefour.com/golang-null-nil.html - What does nil mean in golang?
https://stackoverflow.com/questions/35983118/what-does-nil-mean-in-golang - nils In Go
https://go101.org/article/nil.html - Go slices are not dynamic arrays
https://appliedgo.net/slices/ - Go-is-no-good (nelze brát doslova)
https://github.com/ksimka/go-is-not-good - Rust vs. Go
https://news.ycombinator.com/item?id=13430108 - Seriál Programovací jazyk Rust
https://www.root.cz/serialy/programovaci-jazyk-rust/ - Modern garbage collection: A look at the Go GC strategy
https://blog.plan99.net/modern-garbage-collection-911ef4f8bd8e - Go GC: Prioritizing low latency and simplicity
https://blog.golang.org/go15gc - Is Golang a good language for embedded systems?
https://www.quora.com/Is-Golang-a-good-language-for-embedded-systems - Running GoLang on an STM32 MCU. A quick tutorial.
https://www.mickmake.com/post/running-golang-on-an-mcu-a-quick-tutorial - Go, Robot, Go! Golang Powered Robotics
https://gobot.io/ - Emgo: Bare metal Go (language for programming embedded systems)
https://github.com/ziutek/emgo - UTF-8 history
https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt - Less is exponentially more
https://commandcenter.blogspot.com/2012/06/less-is-exponentially-more.html - Should I Rust, or Should I Go
https://codeburst.io/should-i-rust-or-should-i-go-59a298e00ea9 - Setting up and using gccgo
https://golang.org/doc/install/gccgo - Elastic Tabstops
http://nickgravgaard.com/elastic-tabstops/ - Strings, bytes, runes and characters in Go
https://blog.golang.org/strings - Datový typ
https://cs.wikipedia.org/wiki/Datov%C3%BD_typ - Seriál o programovacím jazyku Rust: Základní (primitivní) datové typy
https://www.root.cz/clanky/programovaci-jazyk-rust-nahrada-c-nebo-slepa-cesta/#k09 - Seriál o programovacím jazyku Rust: Vytvoření „řezu“ z pole
https://www.root.cz/clanky/prace-s-poli-v-programovacim-jazyku-rust/#k06 - Seriál o programovacím jazyku Rust: Řezy (slice) vektoru
https://www.root.cz/clanky/prace-s-vektory-v-programovacim-jazyku-rust/#k05 - Printf Format Strings
https://www.cprogramming.com/tutorial/printf-format-strings.html - Java: String.format
https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#format-java.lang.String-java.lang.Object…- - Java: format string syntax
https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html#syntax - Selectors
https://golang.org/ref/spec#Selectors - Calling Go code from Python code
http://savorywatt.com/2015/09/18/calling-go-code-from-python-code/ - Go Data Structures: Interfaces
https://research.swtch.com/interfaces - How to use interfaces in Go
http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go - Interfaces in Go (part I)
https://medium.com/golangspec/interfaces-in-go-part-i-4ae53a97479c - Part 21: Goroutines
https://golangbot.com/goroutines/ - Part 22: Channels
https://golangbot.com/channels/ - [Go] Lightweight eventbus with async compatibility for Go
https://github.com/asaskevich/EventBus - What about Trait support in Golang?
https://www.reddit.com/r/golang/comments/8mfykl/what_about_trait_support_in_golang/ - Don't Get Bitten by Pointer vs Non-Pointer Method Receivers in Golang
https://nathanleclaire.com/blog/2014/08/09/dont-get-bitten-by-pointer-vs-non-pointer-method-receivers-in-golang/ - Control Flow
https://en.wikipedia.org/wiki/Control_flow - Structured programming
https://en.wikipedia.org/wiki/Structured_programming - Control Structures
https://www.golang-book.com/books/intro/5 - Control structures – Go if else statement
http://golangtutorials.blogspot.com/2011/06/control-structures-if-else-statement.html - Control structures – Go switch case statement
http://golangtutorials.blogspot.com/2011/06/control-structures-go-switch-case.html - Control structures – Go for loop, break, continue, range
http://golangtutorials.blogspot.com/2011/06/control-structures-go-for-loop-break.html - Goroutine IDs
https://blog.sgmansfield.com/2015/12/goroutine-ids/ - Different ways to pass channels as arguments in function in go (golang)
https://stackoverflow.com/questions/24868859/different-ways-to-pass-channels-as-arguments-in-function-in-go-golang - justforfunc #22: using the Go execution tracer
https://www.youtube.com/watch?v=ySy3sR1LFCQ - Single Function Exit Point
http://wiki.c2.com/?SingleFunctionExitPoint - Entry point
https://en.wikipedia.org/wiki/Entry_point - Why does Go have a GOTO statement?!
https://www.reddit.com/r/golang/comments/kag5q/why_does_go_have_a_goto_statement/ - Effective Go
https://golang.org/doc/effective_go.html - GoClipse: an Eclipse IDE for the Go programming language
http://goclipse.github.io/ - GoClipse Installation
https://github.com/GoClipse/goclipse/blob/latest/documentation/Installation.md#installation - The zero value of a slice is not nil
https://stackoverflow.com/questions/30806931/the-zero-value-of-a-slice-is-not-nil - Go-tcha: When nil != nil
https://dev.to/pauljlucas/go-tcha-when-nil–nil-hic - Nils in Go
https://www.doxsey.net/blog/nils-in-go