Skip to content

Commit

Permalink
shockingly enough the first test showed that i did it all wrong
Browse files Browse the repository at this point in the history
  • Loading branch information
mildwonkey committed Dec 13, 2024
1 parent 0f6054d commit f640c99
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 17 deletions.
9 changes: 7 additions & 2 deletions src/pkg/domains/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@ func (a ApiDomain) makeRequests(ctx context.Context) (types.DomainResources, err
for i, request := range a.Spec.Requests {
if i > 0 { // the first request cannot use outputs
if a.Spec.outputs != nil {
executeTpls(request, a.Spec.outputs)
var err error
request, err = executeTpls(request, a.Spec.outputs)
if err != nil {
/// TODO: better error
return collection, err
}
}
}

Expand Down Expand Up @@ -80,7 +85,6 @@ func (a ApiDomain) makeRequests(ctx context.Context) (types.DomainResources, err
}

if request.Outputs != nil {
// get the value from the dr, it's already closer to yaml-shaped
node, err := yaml.ConvertJSONToYamlNode(string(response.Raw))
if err != nil {
errs = errors.Join(errs, err)
Expand Down Expand Up @@ -115,6 +119,7 @@ func executeTpls(req Request, vars map[string]map[string]interface{}) (Request,
reqUrl, err := url.Parse(urlstr)
if err != nil {
// TODO: error types! this is a copy!
// TODO: we should attempt each template step and return a wrapped error
return modifiedReq, errors.New("invalid request url")
}
modifiedReq.reqURL = reqUrl
Expand Down
71 changes: 56 additions & 15 deletions src/pkg/domains/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package api

import (
"context"
"net/http"
"net/url"
"time"

Expand Down Expand Up @@ -60,7 +61,7 @@ type Request struct {
Method string `json:"method,omitempty" yaml:"method,omitempty"`
Body string `json:"body,omitempty" yaml:"body,omitempty"`
Executable bool `json:"executable,omitempty" yaml:"executable,omitempty"`
Outputs []*Outputs `json:"output,omitempty" yaml:"output,omitempty"`
Outputs []*Output `json:"output,omitempty" yaml:"output,omitempty"`
// ApiOpts specific to this request. If ApiOpts is present, values in the
// ApiSpec-level Options are ignored for this request.
Options *ApiOpts `json:"options,omitempty" yaml:"options,omitempty"`
Expand All @@ -79,30 +80,46 @@ func (r Request) DeepCopy() Request {
Name: r.Name,
URL: r.URL,
Method: r.Method,
Body: r.Body,
Executable: r.Executable,
Options: r.Options.DeepCopy(),
URLTpl: r.URLTpl,
reqURL: copyUrl(r.reqURL),
}

if r.Options != nil {
copy.Options = r.Options.DeepCopy()
}

// params, params template
params := make(map[string]string, len(r.Params))
for k, v := range r.Params {
params[k] = v
if r.Params != nil {
params := make(map[string]string, len(r.Params))
for k, v := range r.Params {
params[k] = v
}
copy.Params = params
}
copy.Params = params

paramTpls := make(map[string]string, len(r.ParamsTpl))
for k, v := range r.ParamsTpl {
paramTpls[k] = v
if r.ParamsTpl != nil {
paramTpls := make(map[string]string, len(r.ParamsTpl))
for k, v := range r.ParamsTpl {
paramTpls[k] = v
}
copy.ParamsTpl = paramTpls
}
copy.Params = paramTpls

// outputs
outputs := make([]*Outputs, len(r.Outputs))
for i := range r.Outputs {
outputs[i] = r.Outputs[i]
if r.Outputs != nil {
outputs := make([]*Output, len(r.Outputs))
for i := range r.Outputs {
outputs[i] = r.Outputs[i]
}
copy.Outputs = outputs
}

if r.reqParameters != nil {
copy.reqParameters = copyUrlValues(r.reqParameters)
}
copy.Outputs = outputs

return copy
}

Expand All @@ -121,7 +138,7 @@ type ApiOpts struct {
proxyURL *url.URL
}

type Outputs struct {
type Output struct {
Name string `json:"name" yaml:"name"` // the output will be addressed by RequestName.OutputName
Path string `json:"path" yaml:"path"` // not really sure what to call this - just go all in with jq? jqpath? jsonpath?
}
Expand All @@ -143,3 +160,27 @@ func (a ApiOpts) DeepCopy() *ApiOpts {

return copy
}

// Copied from net/http to avoid the hall of shame: https://go.dev/src/net/http/clone.go
func copyUrlValues(v url.Values) url.Values {
if v == nil {
return nil
}
// http.Header and url.Values have the same representation, so temporarily
// treat it like http.Header, which does have a clone:
return url.Values(http.Header(v).Clone())
}

// Copied from net/http to avoid the hall of shame: https://go.dev/src/net/http/clone.go
func copyUrl(u *url.URL) *url.URL {
if u == nil {
return nil
}
u2 := new(url.URL)
*u2 = *u
if u.User != nil {
u2.User = new(url.Userinfo)
*u2.User = *u.User
}
return u2
}
67 changes: 67 additions & 0 deletions src/pkg/domains/api/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"encoding/json"
"net/http"
"net/http/httptest"
"net/url"
"reflect"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -145,3 +147,68 @@ func TestGetResources(t *testing.T) {
})
})
}

func TestRequest_DeepCopy(t *testing.T) {
examplecom, err := url.Parse("example.com")
require.NoError(t, err)
params := map[string]string{
"key": "value",
}
queryParameters := url.Values{}
for k, v := range params {
queryParameters.Add(k, v)
}

tests := map[string]struct {
want Request
}{
"zero value": {
Request{},
},
"slightly less zero": {
Request{
Params: make(map[string]string),
Outputs: make([]*Output, 0),
Options: &ApiOpts{},
},
},
"populated request": {
Request{
Name: "get",
URL: "example.com",
Params: map[string]string{
"key": "value",
},
Method: "get",
Body: "corpus",
Executable: false,
Outputs: []*Output{
{
Name: "token",
Path: "get.input.token",
},
},
Options: &ApiOpts{
Headers: map[string]string{
"x-lula-special": "birb",
},
},
URLTpl: `weirder[[.string]]`,
ParamsTpl: map[string]string{
"amapof": `weird[[.string]]`,
},
reqURL: examplecom,
reqParameters: queryParameters,
},
},
}

for name, test := range tests {
t.Run(name, func(t *testing.T) {
got := test.want.DeepCopy()
if !reflect.DeepEqual(got, test.want) {
t.Errorf("wrong result: got\n%#v\nwant:\n%#v\n", got, test.want)
}
})
}
}

0 comments on commit f640c99

Please sign in to comment.