Skip to content

Commit

Permalink
Upgrade generated examples
Browse files Browse the repository at this point in the history
So they use Clue for observability instead of the deprecated Goa middlewares.
  • Loading branch information
raphael committed Jun 23, 2024
1 parent 128cfdb commit d83b7ee
Show file tree
Hide file tree
Showing 67 changed files with 3,282 additions and 3,197 deletions.
16 changes: 8 additions & 8 deletions codegen/example/example_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package example

import (
"bytes"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"goa.design/goa/v3/codegen"
Expand All @@ -16,13 +16,12 @@ func TestExampleCLIFiles(t *testing.T) {
cases := []struct {
Name string
DSL func()
Code string
}{
{"no-server", testdata.NoServerDSL, testdata.NoServerCLIMainCode},
{"single-server-single-host", testdata.SingleServerSingleHostDSL, testdata.SingleServerSingleHostCLIMainCode},
{"single-server-single-host-with-variables", testdata.SingleServerSingleHostWithVariablesDSL, testdata.SingleServerSingleHostWithVariablesCLIMainCode},
{"single-server-multiple-hosts", testdata.SingleServerMultipleHostsDSL, testdata.SingleServerMultipleHostsCLIMainCode},
{"single-server-multiple-hosts-with-variables", testdata.SingleServerMultipleHostsWithVariablesDSL, testdata.SingleServerMultipleHostsWithVariablesCLIMainCode},
{"no-server", testdata.NoServerDSL},
{"single-server-single-host", testdata.SingleServerSingleHostDSL},
{"single-server-single-host-with-variables", testdata.SingleServerSingleHostWithVariablesDSL},
{"single-server-multiple-hosts", testdata.SingleServerMultipleHostsDSL},
{"single-server-multiple-hosts-with-variables", testdata.SingleServerMultipleHostsWithVariablesDSL},
}
for _, c := range cases {
t.Run(c.Name, func(t *testing.T) {
Expand All @@ -37,7 +36,8 @@ func TestExampleCLIFiles(t *testing.T) {
require.NoError(t, s.Write(&buf))
}
code := codegen.FormatTestCode(t, "package foo\n"+buf.String())
assert.Equal(t, c.Code, code)
golden := filepath.Join("testdata", "client-"+c.Name+".golden")
compareOrUpdateGolden(t, code, golden)
})
}
}
4 changes: 2 additions & 2 deletions codegen/example/example_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ func exampleSvrMain(genpkg string, root *expr.RootExpr, svr *expr.ServerExpr) *c
{Path: "context"},
{Path: "flag"},
{Path: "fmt"},
{Path: "log"},
{Path: "net"},
{Path: "net/url"},
{Path: "os"},
Expand All @@ -44,7 +43,8 @@ func exampleSvrMain(genpkg string, root *expr.RootExpr, svr *expr.ServerExpr) *c
{Path: "sync"},
{Path: "syscall"},
{Path: "time"},
codegen.GoaImport("middleware"),
{Path: "goa.design/clue/debug"},
{Path: "goa.design/clue/log"},
}

// Iterate through services listed in the server expression.
Expand Down
60 changes: 44 additions & 16 deletions codegen/example/example_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package example

import (
"bytes"
"flag"
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -13,29 +16,46 @@ import (
"goa.design/goa/v3/expr"
)

// updateGolden is true when -w is passed to `go test`, e.g. `go test ./... -w`
var updateGolden = false

func init() {
flag.BoolVar(&updateGolden, "w", false, "update golden files")
}

func compareOrUpdateGolden(t *testing.T, code, golden string) {
t.Helper()
if updateGolden {
require.NoError(t, os.MkdirAll(filepath.Dir(golden), 0755))
require.NoError(t, os.WriteFile(golden, []byte(code), 0644))
return
}
data, err := os.ReadFile(golden)
require.NoError(t, err)
assert.Equal(t, string(data), code)
}

func TestExampleServerFiles(t *testing.T) {
cases := []struct {
Name string
DSL func()
Code string
}{
{"no-server", testdata.NoServerDSL, testdata.NoServerServerMainCode},
{"same-api-service-name", testdata.SameAPIServiceNameDSL, testdata.SameAPIServiceNameServerMainCode},
{"single-server-single-host", testdata.SingleServerSingleHostDSL, testdata.SingleServerSingleHostServerMainCode},
{"single-server-single-host-with-variables", testdata.SingleServerSingleHostWithVariablesDSL, testdata.SingleServerSingleHostWithVariablesServerMainCode},
{"server-hosting-service-with-file-server", testdata.ServerHostingServiceWithFileServerDSL, testdata.ServerHostingServiceWithFileServerServerMainCode},
{"server-hosting-service-subset", testdata.ServerHostingServiceSubsetDSL, testdata.ServerHostingServiceSubsetServerMainCode},
{"server-hosting-multiple-services", testdata.ServerHostingMultipleServicesDSL, testdata.ServerHostingMultipleServicesServerMainCode},
{"single-server-multiple-hosts", testdata.SingleServerMultipleHostsDSL, testdata.SingleServerMultipleHostsServerMainCode},
{"single-server-multiple-hosts-with-variables", testdata.SingleServerMultipleHostsWithVariablesDSL, testdata.SingleServerMultipleHostsWithVariablesServerMainCode},
{"service-name-with-spaces", testdata.NamesWithSpacesDSL, testdata.NamesWithSpacesServerMainCode},
{"service-for-only-http", testdata.ServiceForOnlyHTTPDSL, testdata.ServiceForOnlyHTTPServerMainCode},
{"sercice-for-only-grpc", testdata.ServiceForOnlyGRPCDSL, testdata.ServiceForOnlyGRPCServerMainCode},
{"service-for-http-and-part-of-grpc", testdata.ServiceForHTTPAndPartOfGRPCDSL, testdata.ServiceForHTTPAndPartOfGRPCServerMainCode},
{"no-server", testdata.NoServerDSL},
{"same-api-service-name", testdata.SameAPIServiceNameDSL},
{"single-server-single-host", testdata.SingleServerSingleHostDSL},
{"single-server-single-host-with-variables", testdata.SingleServerSingleHostWithVariablesDSL},
{"server-hosting-service-with-file-server", testdata.ServerHostingServiceWithFileServerDSL},
{"server-hosting-service-subset", testdata.ServerHostingServiceSubsetDSL},
{"server-hosting-multiple-services", testdata.ServerHostingMultipleServicesDSL},
{"single-server-multiple-hosts", testdata.SingleServerMultipleHostsDSL},
{"single-server-multiple-hosts-with-variables", testdata.SingleServerMultipleHostsWithVariablesDSL},
{"service-name-with-spaces", testdata.NamesWithSpacesDSL},
{"service-for-only-http", testdata.ServiceForOnlyHTTPDSL},
{"sercice-for-only-grpc", testdata.ServiceForOnlyGRPCDSL},
{"service-for-http-and-part-of-grpc", testdata.ServiceForHTTPAndPartOfGRPCDSL},
}
for _, c := range cases {
t.Run(c.Name, func(t *testing.T) {
// reset global variable
service.Services = make(service.ServicesData)
Servers = make(ServersData)
codegen.RunDSL(t, c.DSL)
Expand All @@ -47,7 +67,15 @@ func TestExampleServerFiles(t *testing.T) {
require.NoError(t, s.Write(&buf))
}
code := codegen.FormatTestCode(t, "package foo\n"+buf.String())
assert.Equal(t, c.Code, code)
golden := filepath.Join("testdata", "server-"+c.Name+".golden")
if updateGolden {
require.NoError(t, os.MkdirAll(filepath.Dir(golden), 0755))
require.NoError(t, os.WriteFile(golden, []byte(code), 0644))
return
}
data, err := os.ReadFile(golden)
require.NoError(t, err)
assert.Equal(t, string(data), code)
})
}
}
4 changes: 2 additions & 2 deletions codegen/example/templates/server_end.go.tpl
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@


{{ comment "Wait for signal." }}
logger.Printf("exiting (%v)", <-errc)
log.Printf(ctx, "exiting (%v)", <-errc)

{{ comment "Send cancellation signal to the goroutines." }}
cancel()

wg.Wait()
logger.Println("exited")
log.Printf(ctx, "exited")
}
2 changes: 2 additions & 0 deletions codegen/example/templates/server_endpoints.go.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
{{- range .Services }}
{{- if .Methods }}
{{ .VarName }}Endpoints = {{ .PkgName }}.NewEndpoints({{ .VarName }}Svc)
{{ .VarName }}Endpoints.Use(debug.LogPayloads())
{{ .VarName }}Endpoints.Use(log.Endpoint)
{{- end }}
{{- end }}
}
Expand Down
10 changes: 5 additions & 5 deletions codegen/example/templates/server_handler.go.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@
}
}
if !{{ .VarName }}Seen {
logger.Fatalf("invalid value for URL '{{ .Name }}' variable: %q (valid values: {{ join .Values "," }})\n", *{{ .VarName }}F)
log.Fatalf(ctx, "invalid value for URL '{{ .Name }}' variable: %q (valid values: {{ join .Values "," }})\n", *{{ .VarName }}F)
}
{{- end }}
addr = strings.Replace(addr, "{{ printf "{%s}" .Name }}", *{{ .VarName }}F, -1)
{{- end }}
u, err := url.Parse(addr)
if err != nil {
logger.Fatalf("invalid URL %#v: %s\n", addr, err)
log.Fatalf(ctx, "invalid URL %#v: %s\n", addr, err)
}
if *secureF {
u.Scheme = "{{ $u.Transport.Type }}s"
Expand All @@ -38,17 +38,17 @@
if *{{ $u.Transport.Type }}PortF != "" {
h, _, err := net.SplitHostPort(u.Host)
if err != nil {
logger.Fatalf("invalid URL %#v: %s\n", u.Host, err)
log.Fatalf(ctx, "invalid URL %#v: %s\n", u.Host, err)
}
u.Host = net.JoinHostPort(h, *{{ $u.Transport.Type }}PortF)
} else if u.Port() == "" {
u.Host = net.JoinHostPort(u.Host, "{{ $u.Port }}")
}
handle{{ toUpper $u.Transport.Name }}Server(ctx, u, {{ range $t := $.Server.Transports }}{{ if eq $t.Type $u.Transport.Type }}{{ range $s := $t.Services }}{{ range $.Services }}{{ if eq $s .Name }}{{ if .Methods }}{{ .VarName }}Endpoints, {{ end }}{{ end }}{{ end }}{{ end }}{{ end }}{{ end }}&wg, errc, logger, *dbgF)
handle{{ toUpper $u.Transport.Name }}Server(ctx, u, {{ range $t := $.Server.Transports }}{{ if eq $t.Type $u.Transport.Type }}{{ range $s := $t.Services }}{{ range $.Services }}{{ if eq $s .Name }}{{ if .Methods }}{{ .VarName }}Endpoints, {{ end }}{{ end }}{{ end }}{{ end }}{{ end }}{{ end }}&wg, errc, *dbgF)
}
{{- end }}
{{ end }}
{{- end }}
default:
logger.Fatalf("invalid host argument: %q (valid hosts: {{ join .Server.AvailableHosts "|" }})\n", *hostF)
log.Fatalf(ctx, "invalid host argument: %q (valid hosts: {{ join .Server.AvailableHosts "|" }})\n", *hostF)
}
2 changes: 1 addition & 1 deletion codegen/example/templates/server_interrupts.go.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@
}()

var wg sync.WaitGroup
ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithCancel(ctx)
16 changes: 10 additions & 6 deletions codegen/example/templates/server_logger.go.tpl
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@


{{ comment "Setup logger. Replace logger with your own log package of choice." }}
var (
logger *log.Logger
)
{
logger = log.New(os.Stderr, "[{{ .APIPkg }}] ", log.Ltime)
}
format := log.FormatJSON
if log.IsTerminal() {
format = log.FormatTerminal
}
ctx := log.Context(context.Background(), log.WithFormat(format))
if *dbgF {
ctx = log.Context(ctx, log.WithDebug())
log.Debugf(ctx, "debug logs enabled")
}
log.Print(ctx, log.KV{K: "http-port", V: *httpPortF})
2 changes: 1 addition & 1 deletion codegen/example/templates/server_services.go.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
{
{{- range .Services }}
{{- if .Methods }}
{{ .VarName }}Svc = {{ $.APIPkg }}.New{{ .StructName }}(logger)
{{ .VarName }}Svc = {{ $.APIPkg }}.New{{ .StructName }}()
{{- end }}
{{- end }}
}
Expand Down
108 changes: 108 additions & 0 deletions codegen/example/testdata/client-no-server.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
func main() {
var (
hostF = flag.String("host", "localhost", "Server host (valid values: localhost)")
addrF = flag.String("url", "", "URL to service host")

verboseF = flag.Bool("verbose", false, "Print request and response details")
vF = flag.Bool("v", false, "Print request and response details")
timeoutF = flag.Int("timeout", 30, "Maximum number of seconds to wait for response")
)
flag.Usage = usage
flag.Parse()
var (
addr string
timeout int
debug bool
)
{
addr = *addrF
if addr == "" {
switch *hostF {
case "localhost":
addr = "http://localhost:80"
default:
fmt.Fprintf(os.Stderr, "invalid host argument: %q (valid hosts: localhost)\n", *hostF)
os.Exit(1)
}
}
timeout = *timeoutF
debug = *verboseF || *vF
}

var (
scheme string
host string
)
{
u, err := url.Parse(addr)
if err != nil {
fmt.Fprintf(os.Stderr, "invalid URL %#v: %s\n", addr, err)
os.Exit(1)
}
scheme = u.Scheme
host = u.Host
}
var (
endpoint goa.Endpoint
payload any
err error
)
{
switch scheme {
case "http", "https":
endpoint, payload, err = doHTTP(scheme, host, timeout, debug)
case "grpc", "grpcs":
endpoint, payload, err = doGRPC(scheme, host, timeout, debug)
default:
fmt.Fprintf(os.Stderr, "invalid scheme: %q (valid schemes: grpc|http)\n", scheme)
os.Exit(1)
}
}
if err != nil {
if err == flag.ErrHelp {
os.Exit(0)
}
fmt.Fprintln(os.Stderr, err.Error())
fmt.Fprintln(os.Stderr, "run '"+os.Args[0]+" --help' for detailed usage.")
os.Exit(1)
}

data, err := endpoint(context.Background(), payload)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}

if data != nil {
m, _ := json.MarshalIndent(data, "", " ")
fmt.Println(string(m))
}
}

func usage() {
fmt.Fprintf(os.Stderr, `%s is a command line client for the test api API.

Usage:
%s [-host HOST][-url URL][-timeout SECONDS][-verbose|-v] SERVICE ENDPOINT [flags]

-host HOST: server host (localhost). valid values: localhost
-url URL: specify service URL overriding host URL (http://localhost:8080)
-timeout: maximum number of seconds to wait for response (30)
-verbose|-v: print request and response details (false)

Commands:
%s
Additional help:
%s SERVICE [ENDPOINT] --help

Example:
%s
`, os.Args[0], os.Args[0], indent(httpUsageCommands()), os.Args[0], indent(httpUsageExamples()))
}

func indent(s string) string {
if s == "" {
return ""
}
return " " + strings.Replace(s, "\n", "\n ", -1)
}
Loading

0 comments on commit d83b7ee

Please sign in to comment.