Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package fortio for openSUSE:Factory checked in at 2022-09-14 13:44:58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/fortio (Old) and /work/SRC/openSUSE:Factory/.fortio.new.2083 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "fortio" Wed Sep 14 13:44:58 2022 rev:20 rq:1003422 version:1.37.1 Changes: -------- --- /work/SRC/openSUSE:Factory/fortio/fortio.changes 2022-09-08 14:23:21.342627638 +0200 +++ /work/SRC/openSUSE:Factory/.fortio.new.2083/fortio.changes 2022-09-14 13:45:10.157922526 +0200 @@ -1,0 +2,12 @@ +Wed Sep 14 05:40:27 UTC 2022 - ka...@b1-systems.de + +- Update to version 1.37.1: + * Allow empty body to be valid for jrpc.HandleCall/Deserialize; allow method override in client (#623) + +------------------------------------------------------------------- +Tue Sep 13 12:43:10 UTC 2022 - ka...@b1-systems.de + +- Update to version 1.37.0: + * Better names for CallNoPayload -> Get and CallWithPayload -> Fetch (#622) + +------------------------------------------------------------------- Old: ---- fortio-1.36.0.tar.gz New: ---- fortio-1.37.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ fortio.spec ++++++ --- /var/tmp/diff_new_pack.TqDa6I/_old 2022-09-14 13:45:11.329925477 +0200 +++ /var/tmp/diff_new_pack.TqDa6I/_new 2022-09-14 13:45:11.333925487 +0200 @@ -19,7 +19,7 @@ %define __arch_install_post export NO_BRP_STRIP_DEBUG=true Name: fortio -Version: 1.36.0 +Version: 1.37.1 Release: 0 Summary: Load testing library, command line tool, advanced echo server and web UI License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.TqDa6I/_old 2022-09-14 13:45:11.373925587 +0200 +++ /var/tmp/diff_new_pack.TqDa6I/_new 2022-09-14 13:45:11.377925597 +0200 @@ -3,7 +3,7 @@ <param name="url">https://github.com/fortio/fortio</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">v1.36.0</param> + <param name="revision">v1.37.1</param> <param name="versionformat">@PARENT_TAG@</param> <param name="changesgenerate">enable</param> <param name="versionrewrite-pattern">v(.*)</param> @@ -17,7 +17,7 @@ <param name="compression">gz</param> </service> <service name="go_modules" mode="disabled"> - <param name="archive">fortio-1.36.0.tar.gz</param> + <param name="archive">fortio-1.37.1.tar.gz</param> </service> </services> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.TqDa6I/_old 2022-09-14 13:45:11.401925658 +0200 +++ /var/tmp/diff_new_pack.TqDa6I/_new 2022-09-14 13:45:11.405925668 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/fortio/fortio</param> - <param name="changesrevision">83ce66168fb0bd6958bf91cee578d818dd6671d1</param></service></servicedata> + <param name="changesrevision">0fa89821fab2d9451802ea6195b721d4a94d65a7</param></service></servicedata> (No newline at EOF) ++++++ fortio-1.36.0.tar.gz -> fortio-1.37.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.36.0/Makefile new/fortio-1.37.1/Makefile --- old/fortio-1.36.0/Makefile 2022-09-07 21:40:26.000000000 +0200 +++ new/fortio-1.37.1/Makefile 2022-09-13 19:31:18.000000000 +0200 @@ -58,7 +58,7 @@ local-lint: golangci-lint version - golangci-lint $(DEBUG_LINTERS) run $(LINT_PACKAGES) + golangci-lint --timeout 120s $(DEBUG_LINTERS) run $(LINT_PACKAGES) # Lint everything by default but ok to "make lint LINT_PACKAGES=./fhttp" LINT_PACKAGES:=./... diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.36.0/README.md new/fortio-1.37.1/README.md --- old/fortio-1.36.0/README.md 2022-09-07 21:40:26.000000000 +0200 +++ new/fortio-1.37.1/README.md 2022-09-13 19:31:18.000000000 +0200 @@ -52,13 +52,13 @@ The [releases](https://github.com/fortio/fortio/releases) page has binaries for many OS/architecture combinations (see assets). ```shell -curl -L https://github.com/fortio/fortio/releases/download/v1.36.0/fortio-linux_amd64-1.36.0.tgz \ +curl -L https://github.com/fortio/fortio/releases/download/v1.37.1/fortio-linux_amd64-1.37.1.tgz \ | sudo tar -C / -xvzpf - # or the debian package -wget https://github.com/fortio/fortio/releases/download/v1.36.0/fortio_1.36.0_amd64.deb -dpkg -i fortio_1.36.0_amd64.deb +wget https://github.com/fortio/fortio/releases/download/v1.37.1/fortio_1.37.1_amd64.deb +dpkg -i fortio_1.37.1_amd64.deb # or the rpm -rpm -i https://github.com/fortio/fortio/releases/download/v1.36.0/fortio-1.36.0-1.x86_64.rpm +rpm -i https://github.com/fortio/fortio/releases/download/v1.37.1/fortio-1.37.1-1.x86_64.rpm # and more, see assets in release page ``` @@ -68,7 +68,7 @@ brew install fortio ``` -On Windows, download https://github.com/fortio/fortio/releases/download/v1.36.0/fortio_win_1.36.0.zip and extract `fortio.exe` to any location, then using the Windows Command Prompt: +On Windows, download https://github.com/fortio/fortio/releases/download/v1.37.1/fortio_win_1.37.1.zip and extract `fortio.exe` to any location, then using the Windows Command Prompt: ``` fortio.exe server ``` @@ -116,7 +116,7 @@ <details> <!-- use release/updateFlags.sh to update this section --> <pre> -???????????? 1.36.0 usage: +???????????? 1.37.1 usage: fortio command [flags] target where command is one of: load (load testing), server (starts ui, rest api, http-echo, redirect, proxies, tcp-echo and grpc ping servers), tcp-echo (only diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.36.0/jrpc/jrpcClient.go new/fortio-1.37.1/jrpc/jrpcClient.go --- old/fortio-1.36.0/jrpc/jrpcClient.go 2022-09-07 21:40:26.000000000 +0200 +++ new/fortio-1.37.1/jrpc/jrpcClient.go 2022-09-13 19:31:18.000000000 +0200 @@ -18,6 +18,11 @@ // This package is a true self contained library, that doesn't rely on our logger nor other packages // in fortio/ outside of version/ (which now also doesn't rely on logger or any other package). +// Naming is hard, we have Call, Send, Get, Fetch and FetchBytes pretty much all meaning retrieving data +// from a URL with the variants depending on whether we have something to serialize and if it's bytes +// or struct based in and out. Additionally *URL() variants are for when no additional headers or options +// are needed and the url is just a plain string. If golang supported multiple signatures it would be a single +// method name instead of 8. import ( "bytes" "context" @@ -66,9 +71,13 @@ // Destination is the URL and optional additional headers. type Destination struct { - URL string + URL string + // Default is nil, which means no additional headers. Headers *http.Header + // Default is 0 which means use global timeout. Timeout time.Duration + // Default is "" which will use POST if there is a payload and GET otherwise. + Method string } func (fe *FetchError) Error() string { @@ -91,7 +100,7 @@ return nil, err } } - return CallWithPayload[Q](url, bytes) + return Fetch[Q](url, bytes) } // CallURL is Call without any options/non default headers, timeout etc and just the URL. @@ -99,14 +108,21 @@ return Call[Q](NewDestination(url), payload) } -// CallNoPayload is for an API call without json payload. +// Deprecated: CallNoPayload is for an API call without json payload. +// Use Get() instead. func CallNoPayload[Q any](url *Destination) (*Q, error) { - return CallWithPayload[Q](url, []byte{}) + return Get[Q](url) } -// CallNoPayloadURL short cut for CallNoPayload with url as a string (default Send()/Destination options). -func CallNoPayloadURL[Q any](url string) (*Q, error) { - return CallWithPayload[Q](NewDestination(url), []byte{}) +// Get fetches and deseializes the JSON returned by the Destination into a Q struct. +// Used when there is no json payload to send. +func Get[Q any](url *Destination) (*Q, error) { + return Fetch[Q](url, []byte{}) +} + +// GetURL is Get without additional options (default timeout and headers). +func GetURL[Q any](url string) (*Q, error) { + return Get[Q](NewDestination(url)) } // Serialize serializes the object as json. @@ -117,12 +133,24 @@ // Deserialize deserializes json as a new object of desired type. func Deserialize[Q any](bytes []byte) (*Q, error) { var result Q + if len(bytes) == 0 { + // Allow empty body to be deserialized as empty object. + return &result, nil + } err := json.Unmarshal(bytes, &result) return &result, err // Will return zero object, not nil upon error } -// CallWithPayload is for cases where the payload is already serialized (or empty). +// Deprecated: CallWithPayload use Fetch() instead. func CallWithPayload[Q any](url *Destination, bytes []byte) (*Q, error) { + return Fetch[Q](url, bytes) +} + +// Fetch is for cases where the payload is already serialized (or empty +// but call Get() when empty for clarity). +// Note that if you're looking for the []byte version instead of this +// generics version, it's now called FetchBytes(). +func Fetch[Q any](url *Destination, bytes []byte) (*Q, error) { code, bytes, err := Send(url, bytes) // returns -1 on other errors if err != nil { return nil, err @@ -164,10 +192,17 @@ var req *http.Request var err error var res []byte + method := dest.Method if len(jsonPayload) > 0 { - req, err = http.NewRequestWithContext(ctx, http.MethodPost, dest.URL, bytes.NewReader(jsonPayload)) + if method == "" { + method = http.MethodPost + } + req, err = http.NewRequestWithContext(ctx, method, dest.URL, bytes.NewReader(jsonPayload)) } else { - req, err = http.NewRequestWithContext(ctx, http.MethodGet, dest.URL, nil) + if method == "" { + method = http.MethodGet + } + req, err = http.NewRequestWithContext(ctx, method, dest.URL, nil) } if err != nil { return -1, res, err @@ -197,12 +232,15 @@ } // FetchURL is Send without a payload and no additional options (default timeout and headers). +// Technically this should be called FetchBytesURL(). func FetchURL(url string) (int, []byte, error) { return Send(NewDestination(url), []byte{}) } // Fetch is Send without a payload (so will be a GET request). -func Fetch(url *Destination) (int, []byte, error) { +// Used to be called Fetch() but we needed that shorter name to +// simplify the former CallWithPayload function name. +func FetchBytes(url *Destination) (int, []byte, error) { return Send(url, []byte{}) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.36.0/jrpc/jrpcServer.go new/fortio-1.37.1/jrpc/jrpcServer.go --- old/fortio-1.36.0/jrpc/jrpcServer.go 2022-09-07 21:40:26.000000000 +0200 +++ new/fortio-1.37.1/jrpc/jrpcServer.go 2022-09-13 19:31:18.000000000 +0200 @@ -83,14 +83,11 @@ // HandleCall deserializes the expected type from the request body. // Sample usage code: -// ``` // -// req, err := jrpc.HandleCall[Request](w, r) -// if err != nil { -// _ = jrpc.ReplyError(w, "request error", err) -// } -// -// ```. +// req, err := jrpc.HandleCall[Request](w, r) +// if err != nil { +// _ = jrpc.ReplyError(w, "request error", err) +// } func HandleCall[Q any](w http.ResponseWriter, r *http.Request) (*Q, error) { data, err := io.ReadAll(r.Body) if err != nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.36.0/jrpc/jrpc_test.go new/fortio-1.37.1/jrpc/jrpc_test.go --- old/fortio-1.36.0/jrpc/jrpc_test.go 2022-09-07 21:40:26.000000000 +0200 +++ new/fortio-1.37.1/jrpc/jrpc_test.go 2022-09-13 19:31:18.000000000 +0200 @@ -143,9 +143,21 @@ if res.ConcatenatedStrings != "abcd" { t.Errorf("response doesn't contain expected string: %+v", res) } + // OK case: empty POST + dest := &jrpc.Destination{ + URL: url, + Method: http.MethodPost, // force post (default is get when no payload) + } + res, err = jrpc.Fetch[Response](dest, []byte{}) + if err != nil { + t.Errorf("failed Fetch with POST and empty body: %v", err) + } + if res.Error { + t.Errorf("response unexpectedly marked as failed: %+v", res) + } // Error cases - // Empty request, using Fetch() - code, bytes, err := jrpc.Fetch(jrpc.NewDestination(url)) + // Empty request, using FetchBytes() + code, bytes, err := jrpc.FetchBytes(jrpc.NewDestination(url)) if err != nil { t.Errorf("failed Fetch: %v - %s", err, jrpc.DebugSummary(bytes, 256)) } @@ -176,7 +188,7 @@ if de != nil && !strings.HasPrefix(de.Error(), expected) { t.Errorf("expected dns error to start with %q, got %q", expected, de.Error()) } - // bad json payload sent + // bad json payload sent - call deprecated one for coverage for now, replace with Fetch() when it's gone: errReply, err := jrpc.CallWithPayload[Response](jrpc.NewDestination(url), []byte(`{foo: missing-quotes}`)) if err == nil { t.Errorf("expected error, got nil and %v", res) @@ -195,8 +207,8 @@ if errReply.Exception != expected { t.Errorf("expected Exception in body to be %q, got %+v", expected, errReply) } - // bad json response, using Fetch() - errReply, err = jrpc.CallNoPayloadURL[Response](url) + // bad json response, using GetURL() + errReply, err = jrpc.GetURL[Response](url) if err == nil { t.Errorf("expected error %v", errReply) } @@ -278,7 +290,7 @@ if err == nil { t.Errorf("error expected %v", res) } - expected = "deserialization error, code 500: unexpected end of JSON input (raw reply: )" + expected = "non ok http result, code 500: <nil> (raw reply: )" if err.Error() != expected { t.Errorf("error string expected %q, got %q, %+v", expected, err.Error(), res) } @@ -310,6 +322,7 @@ URL: url, Headers: &inp, } + // use the deprecated for coverage. switch to jrpc.Get() in next version res, err := jrpc.CallNoPayload[http.Header](dest) if err != nil { t.Errorf("failed Call: %v", err) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fortio-1.36.0/rapi/restHandler_test.go new/fortio-1.37.1/rapi/restHandler_test.go --- old/fortio-1.36.0/rapi/restHandler_test.go 2022-09-07 21:40:26.000000000 +0200 +++ new/fortio-1.37.1/rapi/restHandler_test.go 2022-09-13 19:31:18.000000000 +0200 @@ -37,7 +37,7 @@ // Generics ftw. func FetchResult[T any](t *testing.T, url string, jsonPayload string) *T { - r, err := jrpc.CallWithPayload[T](jrpc.NewDestination(url), []byte(jsonPayload)) + r, err := jrpc.Fetch[T](jrpc.NewDestination(url), []byte(jsonPayload)) if err != nil { t.Errorf("Got unexpected error for URL %s: %v - %v", url, err, r) } @@ -63,7 +63,7 @@ // Same as above but when expecting to get an error reply. func GetErrorResult(t *testing.T, url string, jsonPayload string) *jrpc.ServerReply { - r, err := jrpc.CallWithPayload[jrpc.ServerReply](jrpc.NewDestination(url), []byte(jsonPayload)) + r, err := jrpc.Fetch[jrpc.ServerReply](jrpc.NewDestination(url), []byte(jsonPayload)) if err == nil { t.Errorf("Got unexpected no error for URL %s: %v", url, r) } @@ -199,7 +199,7 @@ URL: statusURL, Timeout: 3 * time.Second, } - statuses, err := jrpc.CallNoPayload[StatusReply](statusDest) + statuses, err := jrpc.Get[StatusReply](statusDest) if err != nil { t.Errorf("Error getting status %q: %v", statusURL, err) } @@ -259,7 +259,7 @@ t.Errorf("2nd stop should be noop, got %+v", asyncObj) } // Status should be empty (nothing running) - statuses, err = jrpc.CallNoPayload[StatusReply](statusDest) + statuses, err = jrpc.Get[StatusReply](statusDest) if err != nil { t.Errorf("Error getting status %q: %v", statusURL, err) } @@ -274,7 +274,7 @@ // Get all statuses statusURL = fmt.Sprintf("http://localhost:%d%s%s", addr.Port, uiPath, RestStatusURI) statusDest.URL = statusURL - statuses, err = jrpc.CallNoPayload[StatusReply](statusDest) + statuses, err = jrpc.Get[StatusReply](statusDest) if err != nil { t.Errorf("Error getting status %q: %v", statusURL, err) } @@ -376,7 +376,7 @@ // Get status statusURL := fmt.Sprintf("http://localhost:%d%s%s?runid=%d", addr.Port, uiPath, RestStatusURI, runID) statusDest := jrpc.NewDestination(statusURL) - statuses, err := jrpc.CallNoPayload[StatusReply](statusDest) + statuses, err := jrpc.Get[StatusReply](statusDest) if err != nil { t.Errorf("Error getting status %q: %v", statusURL, err) } @@ -418,7 +418,7 @@ t.Errorf("2nd stop should be noop, got %+v", asyncObj) } // Status should be empty (nothing running) - statuses, err = jrpc.CallNoPayload[StatusReply](statusDest) + statuses, err = jrpc.Get[StatusReply](statusDest) if err != nil { t.Errorf("Error getting status %q: %v", statusURL, err) } @@ -475,7 +475,7 @@ // If jsonPayload isn't empty we POST otherwise get the url. func GetGRPCResult(t *testing.T, url string, jsonPayload string) *fgrpc.GRPCRunnerResults { - r, err := jrpc.CallWithPayload[fgrpc.GRPCRunnerResults](jrpc.NewDestination(url), []byte(jsonPayload)) + r, err := jrpc.Fetch[fgrpc.GRPCRunnerResults](jrpc.NewDestination(url), []byte(jsonPayload)) if err != nil { t.Errorf("Got unexpected err for URL %s: %v", url, err) } ++++++ vendor.tar.gz ++++++