From b22e823308236f8d44b60fa70ab04dfec336a94f Mon Sep 17 00:00:00 2001 From: Jacob Bednarz Date: Fri, 25 Nov 2022 16:01:41 +1100 Subject: [PATCH 1/6] workers: split into separate files and modernise standard Worker methods --- workers.go | 767 ++++------------------------------------ workers_bindings.go | 455 ++++++++++++++++++++++++ workers_domains.go | 48 +++ workers_example_test.go | 400 ++++++++++----------- workers_routes.go | 154 ++++++++ workers_routes_test.go | 348 ++++++++++++++++++ workers_test.go | 697 +++++------------------------------- 7 files changed, 1361 insertions(+), 1508 deletions(-) create mode 100644 workers_bindings.go create mode 100644 workers_domains.go create mode 100644 workers_routes.go create mode 100644 workers_routes_test.go diff --git a/workers.go b/workers.go index 7bc6e9a42..b762acad8 100644 --- a/workers.go +++ b/workers.go @@ -3,10 +3,7 @@ package cloudflare import ( "bytes" "context" - rand "crypto/rand" - "encoding/hex" "encoding/json" - "errors" "fmt" "io" "mime" @@ -23,6 +20,19 @@ type WorkerRequestParams struct { ScriptName string } +type CreateWorkerParams struct { + Name string + Script string + + // Module changes the Content-Type header to specify the script is an + // ES Module syntax script. + Module bool + + // Bindings should be a map where the keys are the binding name, and the + // values are the binding content + Bindings map[string]WorkerBinding +} + // WorkerScriptParams provides a worker script and the associated bindings. type WorkerScriptParams struct { Script string @@ -40,9 +50,7 @@ type WorkerScriptParams struct { // // API reference: https://api.cloudflare.com/#worker-routes-properties type WorkerRoute struct { - ID string `json:"id,omitempty"` Pattern string `json:"pattern"` - Enabled bool `json:"enabled"` // this is deprecated: https://api.cloudflare.com/#worker-filters-deprecated--properties Script string `json:"script,omitempty"` } @@ -87,375 +95,46 @@ type WorkerScriptResponse struct { WorkerScript `json:"result"` } -// WorkerBindingType represents a particular type of binding. -type WorkerBindingType string - -func (b WorkerBindingType) String() string { - return string(b) -} - -const ( - // WorkerDurableObjectBindingType is the type for Durable Object bindings. - WorkerDurableObjectBindingType WorkerBindingType = "durable_object_namespace" - // WorkerInheritBindingType is the type for inherited bindings. - WorkerInheritBindingType WorkerBindingType = "inherit" - // WorkerKvNamespaceBindingType is the type for KV Namespace bindings. - WorkerKvNamespaceBindingType WorkerBindingType = "kv_namespace" - // WorkerWebAssemblyBindingType is the type for Web Assembly module bindings. - WorkerWebAssemblyBindingType WorkerBindingType = "wasm_module" - // WorkerSecretTextBindingType is the type for secret text bindings. - WorkerSecretTextBindingType WorkerBindingType = "secret_text" - // WorkerPlainTextBindingType is the type for plain text bindings. - WorkerPlainTextBindingType WorkerBindingType = "plain_text" - // WorkerServiceBindingType is the type for service bindings. - WorkerServiceBindingType WorkerBindingType = "service" - // WorkerR2BucketBindingType is the type for R2 bucket bindings. - WorkerR2BucketBindingType WorkerBindingType = "r2_bucket" - // WorkerAnalyticsEngineBindingType is the type for Analytics Engine dataset bindings. - WorkerAnalyticsEngineBindingType WorkerBindingType = "analytics_engine" -) - -// WorkerBindingListItem a struct representing an individual binding in a list of bindings. -type WorkerBindingListItem struct { - Name string `json:"name"` - Binding WorkerBinding -} - -// WorkerBindingListResponse wrapper struct for API response to worker binding list API call. -type WorkerBindingListResponse struct { - Response - BindingList []WorkerBindingListItem -} - -// Workers supports multiple types of bindings, e.g. KV namespaces or WebAssembly modules, and each type -// of binding will be represented differently in the upload request body. At a high-level, every binding -// will specify metadata, which is a JSON object with the properties "name" and "type". Some types of bindings -// will also have additional metadata properties. For example, KV bindings also specify the KV namespace. -// In addition to the metadata, some binding types may need to include additional data as part of the -// multipart form. For example, WebAssembly bindings will include the contents of the WebAssembly module. - -// WorkerBinding is the generic interface implemented by all of -// the various binding types. -type WorkerBinding interface { - Type() WorkerBindingType - - // serialize is responsible for returning the binding metadata as well as an optionally - // returning a function that can modify the multipart form body. For example, this is used - // by WebAssembly bindings to add a new part containing the WebAssembly module contents. - serialize(bindingName string) (workerBindingMeta, workerBindingBodyWriter, error) -} - -// workerBindingMeta is the metadata portion of the binding. -type workerBindingMeta = map[string]interface{} - -// workerBindingBodyWriter allows for a binding to add additional parts to the multipart body. -type workerBindingBodyWriter func(*multipart.Writer) error - -// WorkerInheritBinding will just persist whatever binding content was previously uploaded. -type WorkerInheritBinding struct { - // Optional parameter that allows for renaming a binding without changing - // its contents. If `OldName` is empty, the binding name will not be changed. - OldName string -} - -// Type returns the type of the binding. -func (b WorkerInheritBinding) Type() WorkerBindingType { - return WorkerInheritBindingType -} - -func (b WorkerInheritBinding) serialize(bindingName string) (workerBindingMeta, workerBindingBodyWriter, error) { - meta := workerBindingMeta{ - "name": bindingName, - "type": b.Type(), - } - - if b.OldName != "" { - meta["old_name"] = b.OldName - } - - return meta, nil, nil -} - -// WorkerKvNamespaceBinding is a binding to a Workers KV Namespace -// -// https://developers.cloudflare.com/workers/archive/api/resource-bindings/kv-namespaces/ -type WorkerKvNamespaceBinding struct { - NamespaceID string -} +type ListWorkersParams struct{} -// Type returns the type of the binding. -func (b WorkerKvNamespaceBinding) Type() WorkerBindingType { - return WorkerKvNamespaceBindingType -} - -func (b WorkerKvNamespaceBinding) serialize(bindingName string) (workerBindingMeta, workerBindingBodyWriter, error) { - if b.NamespaceID == "" { - return nil, nil, fmt.Errorf(`NamespaceID for binding "%s" cannot be empty`, bindingName) - } - - return workerBindingMeta{ - "name": bindingName, - "type": b.Type(), - "namespace_id": b.NamespaceID, - }, nil, nil -} - -// WorkerDurableObjectBinding is a binding to a Workers Durable Object -// -// https://api.cloudflare.com/#durable-objects-namespace-properties -type WorkerDurableObjectBinding struct { - ClassName string +type DeleteWorkerParams struct { ScriptName string } -// Type returns the type of the binding. -func (b WorkerDurableObjectBinding) Type() WorkerBindingType { - return WorkerDurableObjectBindingType -} - -func (b WorkerDurableObjectBinding) serialize(bindingName string) (workerBindingMeta, workerBindingBodyWriter, error) { - if b.ClassName == "" { - return nil, nil, fmt.Errorf(`ClassName for binding "%s" cannot be empty`, bindingName) - } - - return workerBindingMeta{ - "name": bindingName, - "type": b.Type(), - "class_name": b.ClassName, - "script_name": b.ScriptName, - }, nil, nil -} - -// WorkerWebAssemblyBinding is a binding to a WebAssembly module -// -// https://developers.cloudflare.com/workers/archive/api/resource-bindings/webassembly-modules/ -type WorkerWebAssemblyBinding struct { - Module io.Reader -} - -// Type returns the type of the binding. -func (b WorkerWebAssemblyBinding) Type() WorkerBindingType { - return WorkerWebAssemblyBindingType -} - -func (b WorkerWebAssemblyBinding) serialize(bindingName string) (workerBindingMeta, workerBindingBodyWriter, error) { - partName := getRandomPartName() - - bodyWriter := func(mpw *multipart.Writer) error { - var hdr = textproto.MIMEHeader{} - hdr.Set("content-disposition", fmt.Sprintf(`form-data; name="%s"`, partName)) - hdr.Set("content-type", "application/wasm") - pw, err := mpw.CreatePart(hdr) - if err != nil { - return err - } - _, err = io.Copy(pw, b.Module) - return err - } - - return workerBindingMeta{ - "name": bindingName, - "type": b.Type(), - "part": partName, - }, bodyWriter, nil -} - -// WorkerPlainTextBinding is a binding to plain text -// -// https://developers.cloudflare.com/workers/tooling/api/scripts/#add-a-plain-text-binding -type WorkerPlainTextBinding struct { - Text string -} - -// Type returns the type of the binding. -func (b WorkerPlainTextBinding) Type() WorkerBindingType { - return WorkerPlainTextBindingType -} - -func (b WorkerPlainTextBinding) serialize(bindingName string) (workerBindingMeta, workerBindingBodyWriter, error) { - if b.Text == "" { - return nil, nil, fmt.Errorf(`Text for binding "%s" cannot be empty`, bindingName) - } - - return workerBindingMeta{ - "name": bindingName, - "type": b.Type(), - "text": b.Text, - }, nil, nil -} - -// WorkerSecretTextBinding is a binding to secret text -// -// https://developers.cloudflare.com/workers/tooling/api/scripts/#add-a-secret-text-binding -type WorkerSecretTextBinding struct { - Text string -} - -// Type returns the type of the binding. -func (b WorkerSecretTextBinding) Type() WorkerBindingType { - return WorkerSecretTextBindingType -} - -func (b WorkerSecretTextBinding) serialize(bindingName string) (workerBindingMeta, workerBindingBodyWriter, error) { - if b.Text == "" { - return nil, nil, fmt.Errorf(`Text for binding "%s" cannot be empty`, bindingName) - } - - return workerBindingMeta{ - "name": bindingName, - "type": b.Type(), - "text": b.Text, - }, nil, nil -} - -type WorkerServiceBinding struct { - Service string - Environment *string -} - -func (b WorkerServiceBinding) Type() WorkerBindingType { - return WorkerServiceBindingType -} - -func (b WorkerServiceBinding) serialize(bindingName string) (workerBindingMeta, workerBindingBodyWriter, error) { - if b.Service == "" { - return nil, nil, fmt.Errorf(`Service for binding "%s" cannot be empty`, bindingName) - } - - meta := workerBindingMeta{ - "name": bindingName, - "type": b.Type(), - "service": b.Service, - } - - if b.Environment != nil { - meta["environment"] = *b.Environment - } - - return meta, nil, nil -} - -// WorkerR2BucketBinding is a binding to an R2 bucket. -type WorkerR2BucketBinding struct { - BucketName string -} - -// Type returns the type of the binding. -func (b WorkerR2BucketBinding) Type() WorkerBindingType { - return WorkerR2BucketBindingType -} - -func (b WorkerR2BucketBinding) serialize(bindingName string) (workerBindingMeta, workerBindingBodyWriter, error) { - if b.BucketName == "" { - return nil, nil, fmt.Errorf(`BucketName for binding "%s" cannot be empty`, bindingName) - } - - return workerBindingMeta{ - "name": bindingName, - "type": b.Type(), - "bucket_name": b.BucketName, - }, nil, nil -} - -// WorkerAnalyticsEngineBinding is a binding to an Analytics Engine dataset. -type WorkerAnalyticsEngineBinding struct { - Dataset string -} - -// Type returns the type of the binding. -func (b WorkerAnalyticsEngineBinding) Type() WorkerBindingType { - return WorkerAnalyticsEngineBindingType -} - -func (b WorkerAnalyticsEngineBinding) serialize(bindingName string) (workerBindingMeta, workerBindingBodyWriter, error) { - if b.Dataset == "" { - return nil, nil, fmt.Errorf(`Dataset for binding "%s" cannot be empty`, bindingName) - } - - return workerBindingMeta{ - "name": bindingName, - "type": b.Type(), - "dataset": b.Dataset, - }, nil, nil -} - -// Each binding that adds a part to the multipart form body will need -// a unique part name so we just generate a random 128bit hex string. -func getRandomPartName() string { - randBytes := make([]byte, 16) - rand.Read(randBytes) //nolint:errcheck - return hex.EncodeToString(randBytes) -} - // DeleteWorker deletes worker for a zone. // // API reference: https://api.cloudflare.com/#worker-script-delete-worker -func (api *API) DeleteWorker(ctx context.Context, requestParams *WorkerRequestParams) (WorkerScriptResponse, error) { - // if ScriptName is provided we will treat as org request - if requestParams.ScriptName != "" { - return api.deleteWorkerWithName(ctx, requestParams.ScriptName) - } - uri := fmt.Sprintf("/zones/%s/workers/script", requestParams.ZoneID) +func (api *API) DeleteWorker(ctx context.Context, rc *ResourceContainer, params DeleteWorkerParams) error { + uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s", rc.Identifier, params.ScriptName) res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil) + var r WorkerScriptResponse if err != nil { - return r, err + return err } + err = json.Unmarshal(res, &r) if err != nil { - return r, fmt.Errorf("%s: %w", errUnmarshalError, err) + return fmt.Errorf("%s: %w", errUnmarshalError, err) } - return r, nil + + return nil } -// DeleteWorkerWithName deletes worker for a zone. -// Sccount must be specified as api option https://godoc.org/github.com/cloudflare/cloudflare-go#UsingAccount +// GetWorker fetch raw script content for your worker returns string containing +// worker code js. // // API reference: https://developers.cloudflare.com/workers/tooling/api/scripts/ -func (api *API) deleteWorkerWithName(ctx context.Context, scriptName string) (WorkerScriptResponse, error) { - if api.AccountID == "" { - return WorkerScriptResponse{}, errors.New("account ID required") - } - uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s", api.AccountID, scriptName) - res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil) - var r WorkerScriptResponse - if err != nil { - return r, err - } - err = json.Unmarshal(res, &r) - if err != nil { - return r, fmt.Errorf("%s: %w", errUnmarshalError, err) +func (api *API) GetWorker(ctx context.Context, rc *ResourceContainer, scriptName string) (WorkerScriptResponse, error) { + if rc.Level != AccountRouteLevel { + return WorkerScriptResponse{}, fmt.Errorf(errInvalidResourceContainerAccess, ZoneRouteLevel) } - return r, nil -} -// DownloadWorker fetch raw script content for your worker returns []byte containing worker code js -// -// API reference: https://api.cloudflare.com/#worker-script-download-worker -func (api *API) DownloadWorker(ctx context.Context, requestParams *WorkerRequestParams) (WorkerScriptResponse, error) { - if requestParams.ScriptName != "" { - return api.downloadWorkerWithName(ctx, requestParams.ScriptName) - } - uri := fmt.Sprintf("/zones/%s/workers/script", requestParams.ZoneID) - res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) - var r WorkerScriptResponse - if err != nil { - return r, err + if rc.Identifier == "" { + return WorkerScriptResponse{}, ErrMissingIdentifier } - r.Script = string(res) - r.Module = false - r.Success = true - return r, nil -} -// DownloadWorkerWithName fetch raw script content for your worker returns string containing worker code js -// -// API reference: https://developers.cloudflare.com/workers/tooling/api/scripts/ -func (api *API) downloadWorkerWithName(ctx context.Context, scriptName string) (WorkerScriptResponse, error) { - if api.AccountID == "" { - return WorkerScriptResponse{}, errors.New("account ID required") - } - uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s", api.AccountID, scriptName) + uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s", rc.Identifier, scriptName) res, err := api.makeRequestContextWithHeadersComplete(ctx, http.MethodGet, uri, nil, nil) var r WorkerScriptResponse if err != nil { @@ -486,233 +165,96 @@ func (api *API) downloadWorkerWithName(ctx context.Context, scriptName string) ( return r, nil } -// ListWorkerBindings returns all the bindings for a particular worker. -func (api *API) ListWorkerBindings(ctx context.Context, requestParams *WorkerRequestParams) (WorkerBindingListResponse, error) { - if requestParams.ScriptName == "" { - return WorkerBindingListResponse{}, errors.New("ScriptName is required") - } - if api.AccountID == "" { - return WorkerBindingListResponse{}, errors.New("account ID required") - } - - uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s/bindings", api.AccountID, requestParams.ScriptName) - - var jsonRes struct { - Response - Bindings []workerBindingMeta `json:"result"` - } - var r WorkerBindingListResponse - res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) - if err != nil { - return r, err - } - err = json.Unmarshal(res, &jsonRes) - if err != nil { - return r, fmt.Errorf("%s: %w", errUnmarshalError, err) - } - - r = WorkerBindingListResponse{ - Response: jsonRes.Response, - BindingList: make([]WorkerBindingListItem, 0, len(jsonRes.Bindings)), - } - for _, jsonBinding := range jsonRes.Bindings { - name, ok := jsonBinding["name"].(string) - if !ok { - return r, fmt.Errorf("Binding missing name %v", jsonBinding) - } - bType, ok := jsonBinding["type"].(string) - if !ok { - return r, fmt.Errorf("Binding missing type %v", jsonBinding) - } - bindingListItem := WorkerBindingListItem{ - Name: name, - } - - switch WorkerBindingType(bType) { - case WorkerDurableObjectBindingType: - class_name := jsonBinding["class_name"].(string) - script_name := jsonBinding["script_name"].(string) - bindingListItem.Binding = WorkerDurableObjectBinding{ - ClassName: class_name, - ScriptName: script_name, - } - case WorkerKvNamespaceBindingType: - namespaceID := jsonBinding["namespace_id"].(string) - bindingListItem.Binding = WorkerKvNamespaceBinding{ - NamespaceID: namespaceID, - } - case WorkerWebAssemblyBindingType: - bindingListItem.Binding = WorkerWebAssemblyBinding{ - Module: &bindingContentReader{ - ctx: ctx, - api: api, - requestParams: requestParams, - bindingName: name, - }, - } - case WorkerPlainTextBindingType: - text := jsonBinding["text"].(string) - bindingListItem.Binding = WorkerPlainTextBinding{ - Text: text, - } - case WorkerServiceBindingType: - service := jsonBinding["service"].(string) - environment := jsonBinding["environment"].(string) - bindingListItem.Binding = WorkerServiceBinding{ - Service: service, - Environment: &environment, - } - case WorkerSecretTextBindingType: - bindingListItem.Binding = WorkerSecretTextBinding{} - case WorkerR2BucketBindingType: - bucketName := jsonBinding["bucket_name"].(string) - bindingListItem.Binding = WorkerR2BucketBinding{ - BucketName: bucketName, - } - case WorkerAnalyticsEngineBindingType: - dataset := jsonBinding["dataset"].(string) - bindingListItem.Binding = WorkerAnalyticsEngineBinding{ - Dataset: dataset, - } - default: - bindingListItem.Binding = WorkerInheritBinding{} - } - r.BindingList = append(r.BindingList, bindingListItem) - } - - return r, nil -} - -// bindingContentReader is an io.Reader that will lazily load the -// raw bytes for a binding from the API when the Read() method -// is first called. This is only useful for binding types -// that store raw bytes, like WebAssembly modules. -type bindingContentReader struct { - api *API - requestParams *WorkerRequestParams - ctx context.Context - bindingName string - content []byte - position int -} - -func (b *bindingContentReader) Read(p []byte) (n int, err error) { - // Lazily load the content when Read() is first called - if b.content == nil { - uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s/bindings/%s/content", b.api.AccountID, b.requestParams.ScriptName, b.bindingName) - res, err := b.api.makeRequestContext(b.ctx, http.MethodGet, uri, nil) - if err != nil { - return 0, err - } - b.content = res - } - - if b.position >= len(b.content) { - return 0, io.EOF - } - - bytesRemaining := len(b.content) - b.position - bytesToProcess := 0 - if len(p) < bytesRemaining { - bytesToProcess = len(p) - } else { - bytesToProcess = bytesRemaining - } - - for i := 0; i < bytesToProcess; i++ { - p[i] = b.content[b.position] - b.position = b.position + 1 - } - - return bytesToProcess, nil -} - -// ListWorkerScripts returns list of worker scripts for given account. +// ListWorkers returns list of Workers for given account. // // API reference: https://developers.cloudflare.com/workers/tooling/api/scripts/ -func (api *API) ListWorkerScripts(ctx context.Context) (WorkerListResponse, error) { - if api.AccountID == "" { - return WorkerListResponse{}, errors.New("account ID required") +func (api *API) ListWorkers(ctx context.Context, rc *ResourceContainer, params ListWorkersParams) (WorkerListResponse, error) { + if rc.Identifier == "" { + return WorkerListResponse{}, ErrMissingAccountID } - uri := fmt.Sprintf("/accounts/%s/workers/scripts", api.AccountID) + + uri := fmt.Sprintf("/accounts/%s/workers/scripts", rc.Identifier) res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) if err != nil { return WorkerListResponse{}, err } + var r WorkerListResponse err = json.Unmarshal(res, &r) if err != nil { return WorkerListResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) } + return r, nil } -// UploadWorker push raw script content for your worker. +// UploadWorker pushes raw script content for your Worker. // // API reference: https://api.cloudflare.com/#worker-script-upload-worker -func (api *API) UploadWorker(ctx context.Context, requestParams *WorkerRequestParams, params *WorkerScriptParams) (WorkerScriptResponse, error) { - if params.Module { - return api.UploadWorkerWithBindings(ctx, requestParams, params) - } - - contentType := "application/javascript" - if requestParams.ScriptName != "" { - return api.uploadWorkerWithName(ctx, requestParams.ScriptName, contentType, []byte(params.Script)) +func (api *API) UploadWorker(ctx context.Context, rc *ResourceContainer, params CreateWorkerParams) (WorkerScriptResponse, error) { + var ( + contentType = "application/javascript" + err error + body []byte + ) + + if params.Module || len(params.Bindings) > 0 { + contentType, body, err = formatMultipartBody(params) + if err != nil { + return WorkerScriptResponse{}, err + } } - return api.uploadWorkerForZone(ctx, requestParams.ZoneID, contentType, []byte(params.Script)) -} -// UploadWorkerWithBindings push raw script content and bindings for your worker -// -// API reference: https://api.cloudflare.com/#worker-script-upload-worker -func (api *API) UploadWorkerWithBindings(ctx context.Context, requestParams *WorkerRequestParams, data *WorkerScriptParams) (WorkerScriptResponse, error) { - contentType, body, err := formatMultipartBody(data) - if err != nil { - return WorkerScriptResponse{}, err - } - if requestParams.ScriptName != "" { - return api.uploadWorkerWithName(ctx, requestParams.ScriptName, contentType, body) + if rc.Level == AccountRouteLevel { + return api.uploadWorkerWithName(ctx, rc, params.Name, contentType, []byte(body)) + } else { + return api.uploadWorkerForZone(ctx, rc, contentType, []byte(body)) } - return api.uploadWorkerForZone(ctx, requestParams.ZoneID, contentType, body) } -func (api *API) uploadWorkerForZone(ctx context.Context, zoneID, contentType string, body []byte) (WorkerScriptResponse, error) { - uri := fmt.Sprintf("/zones/%s/workers/script", zoneID) +func (api *API) uploadWorkerForZone(ctx context.Context, rc *ResourceContainer, contentType string, body []byte) (WorkerScriptResponse, error) { + uri := fmt.Sprintf("/zones/%s/workers/script", rc.Identifier) headers := make(http.Header) headers.Set("Content-Type", contentType) + res, err := api.makeRequestContextWithHeaders(ctx, http.MethodPut, uri, body, headers) var r WorkerScriptResponse if err != nil { return r, err } + err = json.Unmarshal(res, &r) if err != nil { return r, fmt.Errorf("%s: %w", errUnmarshalError, err) } + return r, nil } -func (api *API) uploadWorkerWithName(ctx context.Context, scriptName, contentType string, body []byte) (WorkerScriptResponse, error) { - if api.AccountID == "" { - return WorkerScriptResponse{}, errors.New("account ID required") +func (api *API) uploadWorkerWithName(ctx context.Context, rc *ResourceContainer, scriptName, contentType string, body []byte) (WorkerScriptResponse, error) { + if rc.Identifier == "" { + return WorkerScriptResponse{}, ErrMissingAccountID } - uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s", api.AccountID, scriptName) + uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s", rc.Identifier, scriptName) headers := make(http.Header) headers.Set("Content-Type", contentType) res, err := api.makeRequestContextWithHeaders(ctx, http.MethodPut, uri, body, headers) + var r WorkerScriptResponse if err != nil { return r, err } + err = json.Unmarshal(res, &r) if err != nil { return r, fmt.Errorf("%s: %w", errUnmarshalError, err) } + return r, nil } // Returns content-type, body, error. -func formatMultipartBody(params *WorkerScriptParams) (string, []byte, error) { +func formatMultipartBody(params CreateWorkerParams) (string, []byte, error) { var buf = &bytes.Buffer{} var mpw = multipart.NewWriter(buf) defer mpw.Close() @@ -797,174 +339,3 @@ func formatMultipartBody(params *WorkerScriptParams) (string, []byte, error) { return mpw.FormDataContentType(), buf.Bytes(), nil } - -// CreateWorkerRoute creates worker route for a zone -// -// API reference: https://api.cloudflare.com/#worker-filters-create-filter, https://api.cloudflare.com/#worker-routes-create-route -func (api *API) CreateWorkerRoute(ctx context.Context, zoneID string, route WorkerRoute) (WorkerRouteResponse, error) { - pathComponent, err := getRouteEndpoint(route) - if err != nil { - return WorkerRouteResponse{}, err - } - - uri := fmt.Sprintf("/zones/%s/workers/%s", zoneID, pathComponent) - res, err := api.makeRequestContext(ctx, http.MethodPost, uri, route) - if err != nil { - return WorkerRouteResponse{}, err - } - var r WorkerRouteResponse - err = json.Unmarshal(res, &r) - if err != nil { - return WorkerRouteResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) - } - return r, nil -} - -// DeleteWorkerRoute deletes worker route for a zone -// -// API reference: https://api.cloudflare.com/#worker-routes-delete-route -func (api *API) DeleteWorkerRoute(ctx context.Context, zoneID string, routeID string) (WorkerRouteResponse, error) { - uri := fmt.Sprintf("/zones/%s/workers/routes/%s", zoneID, routeID) - res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil) - if err != nil { - return WorkerRouteResponse{}, err - } - var r WorkerRouteResponse - err = json.Unmarshal(res, &r) - if err != nil { - return WorkerRouteResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) - } - return r, nil -} - -// ListWorkerRoutes returns list of worker routes -// -// API reference: https://api.cloudflare.com/#worker-filters-list-filters, https://api.cloudflare.com/#worker-routes-list-routes -func (api *API) ListWorkerRoutes(ctx context.Context, zoneID string) (WorkerRoutesResponse, error) { - pathComponent := "filters" - // Unfortunately we don't have a good signal of whether the user is wanting - // to use the deprecated filters endpoint (https://api.cloudflare.com/#worker-filters-list-filters) - // or the multi-script routes endpoint (https://api.cloudflare.com/#worker-script-list-workers) - // - // The filters endpoint does not support API tokens, so if an API token is specified we need to use - // the routes endpoint. Otherwise, since the multi-script API endpoints that operate on a script - // require an AccountID, we assume that anyone specifying an AccountID is using the routes endpoint. - // This is likely too presumptuous. In the next major version, we should just remove the deprecated - // filter endpoints entirely to avoid this ambiguity. - if api.AccountID != "" || api.APIToken != "" { - pathComponent = "routes" - } - uri := fmt.Sprintf("/zones/%s/workers/%s", zoneID, pathComponent) - res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) - if err != nil { - return WorkerRoutesResponse{}, err - } - var r WorkerRoutesResponse - err = json.Unmarshal(res, &r) - if err != nil { - return WorkerRoutesResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) - } - for i := range r.Routes { - route := &r.Routes[i] - // The Enabled flag will not be set in the multi-script API response - // so we manually set it to true if the script name is not empty - // in case any multi-script customers rely on the Enabled field - if route.Script != "" { - route.Enabled = true - } - } - return r, nil -} - -// GetWorkerRoute returns a worker route. -// -// API reference: https://api.cloudflare.com/#worker-routes-get-route -func (api *API) GetWorkerRoute(ctx context.Context, zoneID string, routeID string) (WorkerRouteResponse, error) { - uri := fmt.Sprintf("/zones/%s/workers/routes/%s", zoneID, routeID) - res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) - if err != nil { - return WorkerRouteResponse{}, err - } - var r WorkerRouteResponse - err = json.Unmarshal(res, &r) - if err != nil { - return WorkerRouteResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) - } - return r, nil -} - -// UpdateWorkerRoute updates worker route for a zone. -// -// API reference: https://api.cloudflare.com/#worker-filters-update-filter, https://api.cloudflare.com/#worker-routes-update-route -func (api *API) UpdateWorkerRoute(ctx context.Context, zoneID string, routeID string, route WorkerRoute) (WorkerRouteResponse, error) { - pathComponent, err := getRouteEndpoint(route) - if err != nil { - return WorkerRouteResponse{}, err - } - uri := fmt.Sprintf("/zones/%s/workers/%s/%s", zoneID, pathComponent, routeID) - res, err := api.makeRequestContext(ctx, http.MethodPut, uri, route) - if err != nil { - return WorkerRouteResponse{}, err - } - var r WorkerRouteResponse - err = json.Unmarshal(res, &r) - if err != nil { - return WorkerRouteResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) - } - return r, nil -} - -func getRouteEndpoint(route WorkerRoute) (string, error) { - if route.Script != "" && route.Enabled { - return "", errors.New("Only `Script` or `Enabled` may be specified for a WorkerRoute, not both") - } - - // For backwards-compatibility, fallback to the deprecated filter - // endpoint if Enabled == true - // https://api.cloudflare.com/#worker-filters-deprecated--properties - if route.Enabled { - return "filters", nil - } - - return "routes", nil -} - -type WorkerDomainParams struct { - ZoneID string `json:"zone_id"` - Hostname string `json:"hostname"` - Service string `json:"service"` - Environment string `json:"environment,omitempty"` -} - -type WorkerDomainResult struct { - ID string `json:"id"` - ZoneID string `json:"zone_id"` - ZoneName string `json:"zone_name"` - Hostname string `json:"hostname"` - Service string `json:"service"` - Environment string `json:"environment"` -} - -type WorkerDomainResponse struct { - Response - WorkerDomainResult `json:"result"` -} - -// AttachWorkerToDomain attaches a worker to a zone and hostname -// -// API reference: https://api.cloudflare.com/#worker-domain-attach-to-domain -func (api *API) AttachWorkerToDomain(ctx context.Context, rc *ResourceContainer, params *WorkerDomainParams) (WorkerDomainResponse, error) { - uri := fmt.Sprintf("/accounts/%s/workers/domains", rc.Identifier) - res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params) - if err != nil { - return WorkerDomainResponse{}, err - } - - var r WorkerDomainResponse - err = json.Unmarshal(res, &r) - if err != nil { - return WorkerDomainResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) - } - - return r, nil -} diff --git a/workers_bindings.go b/workers_bindings.go new file mode 100644 index 000000000..7ba01a451 --- /dev/null +++ b/workers_bindings.go @@ -0,0 +1,455 @@ +package cloudflare + +import ( + "context" + rand "crypto/rand" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/textproto" +) + +// WorkerBindingType represents a particular type of binding. +type WorkerBindingType string + +func (b WorkerBindingType) String() string { + return string(b) +} + +const ( + // WorkerDurableObjectBindingType is the type for Durable Object bindings. + WorkerDurableObjectBindingType WorkerBindingType = "durable_object_namespace" + // WorkerInheritBindingType is the type for inherited bindings. + WorkerInheritBindingType WorkerBindingType = "inherit" + // WorkerKvNamespaceBindingType is the type for KV Namespace bindings. + WorkerKvNamespaceBindingType WorkerBindingType = "kv_namespace" + // WorkerWebAssemblyBindingType is the type for Web Assembly module bindings. + WorkerWebAssemblyBindingType WorkerBindingType = "wasm_module" + // WorkerSecretTextBindingType is the type for secret text bindings. + WorkerSecretTextBindingType WorkerBindingType = "secret_text" + // WorkerPlainTextBindingType is the type for plain text bindings. + WorkerPlainTextBindingType WorkerBindingType = "plain_text" + // WorkerServiceBindingType is the type for service bindings. + WorkerServiceBindingType WorkerBindingType = "service" + // WorkerR2BucketBindingType is the type for R2 bucket bindings. + WorkerR2BucketBindingType WorkerBindingType = "r2_bucket" + // WorkerAnalyticsEngineBindingType is the type for Analytics Engine dataset bindings. + WorkerAnalyticsEngineBindingType WorkerBindingType = "analytics_engine" +) + +// WorkerBindingListItem a struct representing an individual binding in a list of bindings. +type WorkerBindingListItem struct { + Name string `json:"name"` + Binding WorkerBinding +} + +// WorkerBindingListResponse wrapper struct for API response to worker binding list API call. +type WorkerBindingListResponse struct { + Response + BindingList []WorkerBindingListItem +} + +// Workers supports multiple types of bindings, e.g. KV namespaces or WebAssembly modules, and each type +// of binding will be represented differently in the upload request body. At a high-level, every binding +// will specify metadata, which is a JSON object with the properties "name" and "type". Some types of bindings +// will also have additional metadata properties. For example, KV bindings also specify the KV namespace. +// In addition to the metadata, some binding types may need to include additional data as part of the +// multipart form. For example, WebAssembly bindings will include the contents of the WebAssembly module. + +// WorkerBinding is the generic interface implemented by all of +// the various binding types. +type WorkerBinding interface { + Type() WorkerBindingType + + // serialize is responsible for returning the binding metadata as well as an optionally + // returning a function that can modify the multipart form body. For example, this is used + // by WebAssembly bindings to add a new part containing the WebAssembly module contents. + serialize(bindingName string) (workerBindingMeta, workerBindingBodyWriter, error) +} + +// workerBindingMeta is the metadata portion of the binding. +type workerBindingMeta = map[string]interface{} + +// workerBindingBodyWriter allows for a binding to add additional parts to the multipart body. +type workerBindingBodyWriter func(*multipart.Writer) error + +// WorkerInheritBinding will just persist whatever binding content was previously uploaded. +type WorkerInheritBinding struct { + // Optional parameter that allows for renaming a binding without changing + // its contents. If `OldName` is empty, the binding name will not be changed. + OldName string +} + +// Type returns the type of the binding. +func (b WorkerInheritBinding) Type() WorkerBindingType { + return WorkerInheritBindingType +} + +func (b WorkerInheritBinding) serialize(bindingName string) (workerBindingMeta, workerBindingBodyWriter, error) { + meta := workerBindingMeta{ + "name": bindingName, + "type": b.Type(), + } + + if b.OldName != "" { + meta["old_name"] = b.OldName + } + + return meta, nil, nil +} + +// WorkerKvNamespaceBinding is a binding to a Workers KV Namespace +// +// https://developers.cloudflare.com/workers/archive/api/resource-bindings/kv-namespaces/ +type WorkerKvNamespaceBinding struct { + NamespaceID string +} + +// Type returns the type of the binding. +func (b WorkerKvNamespaceBinding) Type() WorkerBindingType { + return WorkerKvNamespaceBindingType +} + +func (b WorkerKvNamespaceBinding) serialize(bindingName string) (workerBindingMeta, workerBindingBodyWriter, error) { + if b.NamespaceID == "" { + return nil, nil, fmt.Errorf(`NamespaceID for binding "%s" cannot be empty`, bindingName) + } + + return workerBindingMeta{ + "name": bindingName, + "type": b.Type(), + "namespace_id": b.NamespaceID, + }, nil, nil +} + +// WorkerDurableObjectBinding is a binding to a Workers Durable Object +// +// https://api.cloudflare.com/#durable-objects-namespace-properties +type WorkerDurableObjectBinding struct { + ClassName string + ScriptName string +} + +// Type returns the type of the binding. +func (b WorkerDurableObjectBinding) Type() WorkerBindingType { + return WorkerDurableObjectBindingType +} + +func (b WorkerDurableObjectBinding) serialize(bindingName string) (workerBindingMeta, workerBindingBodyWriter, error) { + if b.ClassName == "" { + return nil, nil, fmt.Errorf(`ClassName for binding "%s" cannot be empty`, bindingName) + } + + return workerBindingMeta{ + "name": bindingName, + "type": b.Type(), + "class_name": b.ClassName, + "script_name": b.ScriptName, + }, nil, nil +} + +// WorkerWebAssemblyBinding is a binding to a WebAssembly module +// +// https://developers.cloudflare.com/workers/archive/api/resource-bindings/webassembly-modules/ +type WorkerWebAssemblyBinding struct { + Module io.Reader +} + +// Type returns the type of the binding. +func (b WorkerWebAssemblyBinding) Type() WorkerBindingType { + return WorkerWebAssemblyBindingType +} + +func (b WorkerWebAssemblyBinding) serialize(bindingName string) (workerBindingMeta, workerBindingBodyWriter, error) { + partName := getRandomPartName() + + bodyWriter := func(mpw *multipart.Writer) error { + var hdr = textproto.MIMEHeader{} + hdr.Set("content-disposition", fmt.Sprintf(`form-data; name="%s"`, partName)) + hdr.Set("content-type", "application/wasm") + pw, err := mpw.CreatePart(hdr) + if err != nil { + return err + } + _, err = io.Copy(pw, b.Module) + return err + } + + return workerBindingMeta{ + "name": bindingName, + "type": b.Type(), + "part": partName, + }, bodyWriter, nil +} + +// WorkerPlainTextBinding is a binding to plain text +// +// https://developers.cloudflare.com/workers/tooling/api/scripts/#add-a-plain-text-binding +type WorkerPlainTextBinding struct { + Text string +} + +// Type returns the type of the binding. +func (b WorkerPlainTextBinding) Type() WorkerBindingType { + return WorkerPlainTextBindingType +} + +func (b WorkerPlainTextBinding) serialize(bindingName string) (workerBindingMeta, workerBindingBodyWriter, error) { + if b.Text == "" { + return nil, nil, fmt.Errorf(`Text for binding "%s" cannot be empty`, bindingName) + } + + return workerBindingMeta{ + "name": bindingName, + "type": b.Type(), + "text": b.Text, + }, nil, nil +} + +// WorkerSecretTextBinding is a binding to secret text +// +// https://developers.cloudflare.com/workers/tooling/api/scripts/#add-a-secret-text-binding +type WorkerSecretTextBinding struct { + Text string +} + +// Type returns the type of the binding. +func (b WorkerSecretTextBinding) Type() WorkerBindingType { + return WorkerSecretTextBindingType +} + +func (b WorkerSecretTextBinding) serialize(bindingName string) (workerBindingMeta, workerBindingBodyWriter, error) { + if b.Text == "" { + return nil, nil, fmt.Errorf(`Text for binding "%s" cannot be empty`, bindingName) + } + + return workerBindingMeta{ + "name": bindingName, + "type": b.Type(), + "text": b.Text, + }, nil, nil +} + +type WorkerServiceBinding struct { + Service string + Environment *string +} + +func (b WorkerServiceBinding) Type() WorkerBindingType { + return WorkerServiceBindingType +} + +func (b WorkerServiceBinding) serialize(bindingName string) (workerBindingMeta, workerBindingBodyWriter, error) { + if b.Service == "" { + return nil, nil, fmt.Errorf(`Service for binding "%s" cannot be empty`, bindingName) + } + + meta := workerBindingMeta{ + "name": bindingName, + "type": b.Type(), + "service": b.Service, + } + + if b.Environment != nil { + meta["environment"] = *b.Environment + } + + return meta, nil, nil +} + +// WorkerR2BucketBinding is a binding to an R2 bucket. +type WorkerR2BucketBinding struct { + BucketName string +} + +// Type returns the type of the binding. +func (b WorkerR2BucketBinding) Type() WorkerBindingType { + return WorkerR2BucketBindingType +} + +func (b WorkerR2BucketBinding) serialize(bindingName string) (workerBindingMeta, workerBindingBodyWriter, error) { + if b.BucketName == "" { + return nil, nil, fmt.Errorf(`BucketName for binding "%s" cannot be empty`, bindingName) + } + + return workerBindingMeta{ + "name": bindingName, + "type": b.Type(), + "bucket_name": b.BucketName, + }, nil, nil +} + +// WorkerAnalyticsEngineBinding is a binding to an Analytics Engine dataset. +type WorkerAnalyticsEngineBinding struct { + Dataset string +} + +// Type returns the type of the binding. +func (b WorkerAnalyticsEngineBinding) Type() WorkerBindingType { + return WorkerAnalyticsEngineBindingType +} + +func (b WorkerAnalyticsEngineBinding) serialize(bindingName string) (workerBindingMeta, workerBindingBodyWriter, error) { + if b.Dataset == "" { + return nil, nil, fmt.Errorf(`Dataset for binding "%s" cannot be empty`, bindingName) + } + + return workerBindingMeta{ + "name": bindingName, + "type": b.Type(), + "dataset": b.Dataset, + }, nil, nil +} + +// Each binding that adds a part to the multipart form body will need +// a unique part name so we just generate a random 128bit hex string. +func getRandomPartName() string { + randBytes := make([]byte, 16) + rand.Read(randBytes) //nolint:errcheck + return hex.EncodeToString(randBytes) +} + +// ListWorkerBindings returns all the bindings for a particular worker. +func (api *API) ListWorkerBindings(ctx context.Context, requestParams *WorkerRequestParams) (WorkerBindingListResponse, error) { + if requestParams.ScriptName == "" { + return WorkerBindingListResponse{}, errors.New("ScriptName is required") + } + if api.AccountID == "" { + return WorkerBindingListResponse{}, errors.New("account ID required") + } + + uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s/bindings", api.AccountID, requestParams.ScriptName) + + var jsonRes struct { + Response + Bindings []workerBindingMeta `json:"result"` + } + var r WorkerBindingListResponse + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return r, err + } + err = json.Unmarshal(res, &jsonRes) + if err != nil { + return r, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + + r = WorkerBindingListResponse{ + Response: jsonRes.Response, + BindingList: make([]WorkerBindingListItem, 0, len(jsonRes.Bindings)), + } + for _, jsonBinding := range jsonRes.Bindings { + name, ok := jsonBinding["name"].(string) + if !ok { + return r, fmt.Errorf("Binding missing name %v", jsonBinding) + } + bType, ok := jsonBinding["type"].(string) + if !ok { + return r, fmt.Errorf("Binding missing type %v", jsonBinding) + } + bindingListItem := WorkerBindingListItem{ + Name: name, + } + + switch WorkerBindingType(bType) { + case WorkerDurableObjectBindingType: + class_name := jsonBinding["class_name"].(string) + script_name := jsonBinding["script_name"].(string) + bindingListItem.Binding = WorkerDurableObjectBinding{ + ClassName: class_name, + ScriptName: script_name, + } + case WorkerKvNamespaceBindingType: + namespaceID := jsonBinding["namespace_id"].(string) + bindingListItem.Binding = WorkerKvNamespaceBinding{ + NamespaceID: namespaceID, + } + case WorkerWebAssemblyBindingType: + bindingListItem.Binding = WorkerWebAssemblyBinding{ + Module: &bindingContentReader{ + ctx: ctx, + api: api, + requestParams: requestParams, + bindingName: name, + }, + } + case WorkerPlainTextBindingType: + text := jsonBinding["text"].(string) + bindingListItem.Binding = WorkerPlainTextBinding{ + Text: text, + } + case WorkerServiceBindingType: + service := jsonBinding["service"].(string) + environment := jsonBinding["environment"].(string) + bindingListItem.Binding = WorkerServiceBinding{ + Service: service, + Environment: &environment, + } + case WorkerSecretTextBindingType: + bindingListItem.Binding = WorkerSecretTextBinding{} + case WorkerR2BucketBindingType: + bucketName := jsonBinding["bucket_name"].(string) + bindingListItem.Binding = WorkerR2BucketBinding{ + BucketName: bucketName, + } + case WorkerAnalyticsEngineBindingType: + dataset := jsonBinding["dataset"].(string) + bindingListItem.Binding = WorkerAnalyticsEngineBinding{ + Dataset: dataset, + } + default: + bindingListItem.Binding = WorkerInheritBinding{} + } + r.BindingList = append(r.BindingList, bindingListItem) + } + + return r, nil +} + +// bindingContentReader is an io.Reader that will lazily load the +// raw bytes for a binding from the API when the Read() method +// is first called. This is only useful for binding types +// that store raw bytes, like WebAssembly modules. +type bindingContentReader struct { + api *API + requestParams *WorkerRequestParams + ctx context.Context + bindingName string + content []byte + position int +} + +func (b *bindingContentReader) Read(p []byte) (n int, err error) { + // Lazily load the content when Read() is first called + if b.content == nil { + uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s/bindings/%s/content", b.api.AccountID, b.requestParams.ScriptName, b.bindingName) + res, err := b.api.makeRequestContext(b.ctx, http.MethodGet, uri, nil) + if err != nil { + return 0, err + } + b.content = res + } + + if b.position >= len(b.content) { + return 0, io.EOF + } + + bytesRemaining := len(b.content) - b.position + bytesToProcess := 0 + if len(p) < bytesRemaining { + bytesToProcess = len(p) + } else { + bytesToProcess = bytesRemaining + } + + for i := 0; i < bytesToProcess; i++ { + p[i] = b.content[b.position] + b.position = b.position + 1 + } + + return bytesToProcess, nil +} diff --git a/workers_domains.go b/workers_domains.go new file mode 100644 index 000000000..e8caea979 --- /dev/null +++ b/workers_domains.go @@ -0,0 +1,48 @@ +package cloudflare + +import ( + "context" + "encoding/json" + "fmt" + "net/http" +) + +type WorkerDomainParams struct { + ZoneID string `json:"zone_id"` + Hostname string `json:"hostname"` + Service string `json:"service"` + Environment string `json:"environment,omitempty"` +} + +type WorkerDomainResult struct { + ID string `json:"id"` + ZoneID string `json:"zone_id"` + ZoneName string `json:"zone_name"` + Hostname string `json:"hostname"` + Service string `json:"service"` + Environment string `json:"environment"` +} + +type WorkerDomainResponse struct { + Response + WorkerDomainResult `json:"result"` +} + +// AttachWorkerToDomain attaches a worker to a zone and hostname +// +// API reference: https://api.cloudflare.com/#worker-domain-attach-to-domain +func (api *API) AttachWorkerToDomain(ctx context.Context, rc *ResourceContainer, params *WorkerDomainParams) (WorkerDomainResponse, error) { + uri := fmt.Sprintf("/accounts/%s/workers/domains", rc.Identifier) + res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params) + if err != nil { + return WorkerDomainResponse{}, err + } + + var r WorkerDomainResponse + err = json.Unmarshal(res, &r) + if err != nil { + return WorkerDomainResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + + return r, nil +} diff --git a/workers_example_test.go b/workers_example_test.go index 2206a3504..f70c7b93a 100644 --- a/workers_example_test.go +++ b/workers_example_test.go @@ -1,206 +1,198 @@ package cloudflare_test -import ( - "context" - "fmt" - "log" - - cloudflare "github.com/cloudflare/cloudflare-go" -) - -var ( - workerScript = "addEventListener('fetch', event => {\n event.passThroughOnException()\nevent.respondWith(handleRequest(event.request))\n})\n\nasync function handleRequest(request) {\n return fetch(request)\n}" -) - -func ExampleAPI_UploadWorker() { - api, err := cloudflare.New(apiKey, user) - if err != nil { - log.Fatal(err) - } - - zoneID, err := api.ZoneIDByName(domain) - if err != nil { - log.Fatal(err) - } - - res, err := api.UploadWorker(context.Background(), &cloudflare.WorkerRequestParams{ZoneID: zoneID}, &cloudflare.WorkerScriptParams{Script: workerScript}) - if err != nil { - log.Fatal(err) - } - fmt.Printf("%+v", res) - - UploadWorkerWithName() -} - -func UploadWorkerWithName() { - api, err := cloudflare.New(apiKey, user, cloudflare.UsingAccount("foo")) - if err != nil { - log.Fatal(err) - } - - res, err := api.UploadWorker(context.Background(), &cloudflare.WorkerRequestParams{ScriptName: "baz"}, &cloudflare.WorkerScriptParams{Script: workerScript}) - if err != nil { - log.Fatal(err) - } - fmt.Printf("%+v", res) -} - -func ExampleAPI_DownloadWorker() { - api, err := cloudflare.New(apiKey, user) - if err != nil { - log.Fatal(err) - } - - zoneID, err := api.ZoneIDByName(domain) - if err != nil { - log.Fatal(err) - } - - res, err := api.DownloadWorker(context.Background(), &cloudflare.WorkerRequestParams{ZoneID: zoneID}) - if err != nil { - log.Fatal(err) - } - fmt.Printf("%+v", res) - - DownloadWorkerWithName() -} - -func DownloadWorkerWithName() { - api, err := cloudflare.New(apiKey, user, cloudflare.UsingAccount("foo")) - if err != nil { - log.Fatal(err) - } - - res, err := api.DownloadWorker(context.Background(), &cloudflare.WorkerRequestParams{ScriptName: "baz"}) - if err != nil { - log.Fatal(err) - } - fmt.Printf("%+v", res) -} - -func ExampleAPI_DeleteWorker() { - api, err := cloudflare.New(apiKey, user) - if err != nil { - log.Fatal(err) - } - - zoneID, err := api.ZoneIDByName(domain) - if err != nil { - log.Fatal(err) - } - res, err := api.DeleteWorker(context.Background(), &cloudflare.WorkerRequestParams{ZoneID: zoneID}) - if err != nil { - log.Fatal(err) - } - fmt.Printf("%+v", res) - - DeleteWorkerWithName() -} - -func DeleteWorkerWithName() { - api, err := cloudflare.New(apiKey, user, cloudflare.UsingAccount("foo")) - if err != nil { - log.Fatal(err) - } - - res, err := api.DeleteWorker(context.Background(), &cloudflare.WorkerRequestParams{ScriptName: "baz"}) - if err != nil { - log.Fatal(err) - } - fmt.Printf("%+v", res) -} - -func ExampleAPI_ListWorkerScripts() { - api, err := cloudflare.New(apiKey, user, cloudflare.UsingAccount("foo")) - if err != nil { - log.Fatal(err) - } - - res, err := api.ListWorkerScripts(context.Background()) - if err != nil { - log.Fatal(err) - } - fmt.Printf("%+v", res.WorkerList) -} - -func ExampleAPI_CreateWorkerRoute() { - api, err := cloudflare.New(apiKey, user) - if err != nil { - log.Fatal(err) - } - - zoneID, err := api.ZoneIDByName(domain) - if err != nil { - log.Fatal(err) - } - route := cloudflare.WorkerRoute{Pattern: "app1.example.com/*", Enabled: true} - res, err := api.CreateWorkerRoute(context.Background(), zoneID, route) - if err != nil { - log.Fatal(err) - } - fmt.Printf("%+v", res) -} - -func ExampleAPI_UpdateWorkerRoute() { - api, err := cloudflare.New(apiKey, user) - if err != nil { - log.Fatal(err) - } - - zoneID, err := api.ZoneIDByName(domain) - if err != nil { - log.Fatal(err) - } - // pull from existing list of routes to perform update on - routesResponse, err := api.ListWorkerRoutes(context.Background(), zoneID) - if err != nil { - log.Fatal(err) - } - route := cloudflare.WorkerRoute{Pattern: "app2.example.com/*", Enabled: true} - // update first route retrieved from the listWorkerRoutes call with details above - res, err := api.UpdateWorkerRoute(context.Background(), zoneID, routesResponse.Routes[0].ID, route) - if err != nil { - log.Fatal(err) - } - fmt.Printf("%+v", res) -} - -func ExampleAPI_ListWorkerRoutes() { - api, err := cloudflare.New(apiKey, user) - if err != nil { - log.Fatal(err) - } - - zoneID, err := api.ZoneIDByName(domain) - if err != nil { - log.Fatal(err) - } - res, err := api.ListWorkerRoutes(context.Background(), zoneID) - if err != nil { - log.Fatal(err) - } - fmt.Printf("%+v", res) -} - -func ExampleAPI_DeleteWorkerRoute() { - api, err := cloudflare.New(apiKey, user) - if err != nil { - log.Fatal(err) - } - - zoneID, err := api.ZoneIDByName(domain) - if err != nil { - log.Fatal(err) - } - // pull from existing list of routes to perform delete on - routesResponse, err := api.ListWorkerRoutes(context.Background(), zoneID) - if err != nil { - log.Fatal(err) - } - // delete first route retrieved from the listWorkerRoutes call - res, err := api.DeleteWorkerRoute(context.Background(), zoneID, routesResponse.Routes[0].ID) - if err != nil { - log.Fatal(err) - } - fmt.Printf("%+v", res) -} +// var ( +// workerScript = "addEventListener('fetch', event => {\n event.passThroughOnException()\nevent.respondWith(handleRequest(event.request))\n})\n\nasync function handleRequest(request) {\n return fetch(request)\n}" +// ) + +// func ExampleAPI_UploadWorker() { +// api, err := cloudflare.New(apiKey, user) +// if err != nil { +// log.Fatal(err) +// } + +// zoneID, err := api.ZoneIDByName(domain) +// if err != nil { +// log.Fatal(err) +// } + +// res, err := api.UploadWorker(context.Background(), &cloudflare.WorkerRequestParams{ZoneID: zoneID}, &cloudflare.WorkerScriptParams{Script: workerScript}) +// if err != nil { +// log.Fatal(err) +// } +// fmt.Printf("%+v", res) + +// UploadWorkerWithName() +// } + +// func UploadWorkerWithName() { +// api, err := cloudflare.New(apiKey, user, cloudflare.UsingAccount("foo")) +// if err != nil { +// log.Fatal(err) +// } + +// res, err := api.UploadWorker(context.Background(), &cloudflare.WorkerRequestParams{ScriptName: "baz"}, &cloudflare.WorkerScriptParams{Script: workerScript}) +// if err != nil { +// log.Fatal(err) +// } +// fmt.Printf("%+v", res) +// } + +// func ExampleAPI_DownloadWorker() { +// api, err := cloudflare.New(apiKey, user) +// if err != nil { +// log.Fatal(err) +// } + +// zoneID, err := api.ZoneIDByName(domain) +// if err != nil { +// log.Fatal(err) +// } + +// res, err := api.DownloadWorker(context.Background(), &cloudflare.WorkerRequestParams{ZoneID: zoneID}) +// if err != nil { +// log.Fatal(err) +// } +// fmt.Printf("%+v", res) + +// DownloadWorkerWithName() +// } + +// func DownloadWorkerWithName() { +// api, err := cloudflare.New(apiKey, user, cloudflare.UsingAccount("foo")) +// if err != nil { +// log.Fatal(err) +// } + +// res, err := api.DownloadWorker(context.Background(), &cloudflare.WorkerRequestParams{ScriptName: "baz"}) +// if err != nil { +// log.Fatal(err) +// } +// fmt.Printf("%+v", res) +// } + +// func ExampleAPI_DeleteWorker() { +// api, err := cloudflare.New(apiKey, user) +// if err != nil { +// log.Fatal(err) +// } + +// zoneID, err := api.ZoneIDByName(domain) +// if err != nil { +// log.Fatal(err) +// } +// res, err := api.DeleteWorker(context.Background(), &cloudflare.WorkerRequestParams{ZoneID: zoneID}) +// if err != nil { +// log.Fatal(err) +// } +// fmt.Printf("%+v", res) + +// DeleteWorkerWithName() +// } + +// func DeleteWorkerWithName() { +// api, err := cloudflare.New(apiKey, user, cloudflare.UsingAccount("foo")) +// if err != nil { +// log.Fatal(err) +// } + +// res, err := api.DeleteWorker(context.Background(), &cloudflare.WorkerRequestParams{ScriptName: "baz"}) +// if err != nil { +// log.Fatal(err) +// } +// fmt.Printf("%+v", res) +// } + +// func ExampleAPI_ListWorkerScripts() { +// api, err := cloudflare.New(apiKey, user, cloudflare.UsingAccount("foo")) +// if err != nil { +// log.Fatal(err) +// } + +// res, err := api.ListWorkerScripts(context.Background()) +// if err != nil { +// log.Fatal(err) +// } +// fmt.Printf("%+v", res.WorkerList) +// } + +// func ExampleAPI_CreateWorkerRoute() { +// api, err := cloudflare.New(apiKey, user) +// if err != nil { +// log.Fatal(err) +// } + +// zoneID, err := api.ZoneIDByName(domain) +// if err != nil { +// log.Fatal(err) +// } +// route := cloudflare.WorkerRoute{Pattern: "app1.example.com/*", Enabled: true} +// res, err := api.CreateWorkerRoute(context.Background(), zoneID, route) +// if err != nil { +// log.Fatal(err) +// } +// fmt.Printf("%+v", res) +// } + +// func ExampleAPI_UpdateWorkerRoute() { +// api, err := cloudflare.New(apiKey, user) +// if err != nil { +// log.Fatal(err) +// } + +// zoneID, err := api.ZoneIDByName(domain) +// if err != nil { +// log.Fatal(err) +// } +// // pull from existing list of routes to perform update on +// routesResponse, err := api.ListWorkerRoutes(context.Background(), zoneID) +// if err != nil { +// log.Fatal(err) +// } +// route := cloudflare.WorkerRoute{Pattern: "app2.example.com/*", Enabled: true} +// // update first route retrieved from the listWorkerRoutes call with details above +// res, err := api.UpdateWorkerRoute(context.Background(), zoneID, routesResponse.Routes[0].ID, route) +// if err != nil { +// log.Fatal(err) +// } +// fmt.Printf("%+v", res) +// } + +// func ExampleAPI_ListWorkerRoutes() { +// api, err := cloudflare.New(apiKey, user) +// if err != nil { +// log.Fatal(err) +// } + +// zoneID, err := api.ZoneIDByName(domain) +// if err != nil { +// log.Fatal(err) +// } +// res, err := api.ListWorkerRoutes(context.Background(), zoneID) +// if err != nil { +// log.Fatal(err) +// } +// fmt.Printf("%+v", res) +// } + +// func ExampleAPI_DeleteWorkerRoute() { +// api, err := cloudflare.New(apiKey, user) +// if err != nil { +// log.Fatal(err) +// } + +// zoneID, err := api.ZoneIDByName(domain) +// if err != nil { +// log.Fatal(err) +// } +// // pull from existing list of routes to perform delete on +// routesResponse, err := api.ListWorkerRoutes(context.Background(), zoneID) +// if err != nil { +// log.Fatal(err) +// } +// // delete first route retrieved from the listWorkerRoutes call +// res, err := api.DeleteWorkerRoute(context.Background(), zoneID, routesResponse.Routes[0].ID) +// if err != nil { +// log.Fatal(err) +// } +// fmt.Printf("%+v", res) +// } diff --git a/workers_routes.go b/workers_routes.go new file mode 100644 index 000000000..31ec7937b --- /dev/null +++ b/workers_routes.go @@ -0,0 +1,154 @@ +package cloudflare + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "net/http" +) + +type ListWorkerRoutes struct{} + +type CreateWorkerRouteParams struct { + Pattern string `json:"pattern"` + Script string `json:"script,omitempty"` +} + +type ListWorkerRoutesParams struct{} + +type UpdateWorkerRouteParams struct { + Pattern string `json:"pattern"` + Script string `json:"script,omitempty"` +} + +// CreateWorkerRoute creates worker route for a zone +// +// API reference: https://api.cloudflare.com/#worker-routes-create-route +func (api *API) CreateWorkerRoute(ctx context.Context, rc *ResourceContainer, params CreateWorkerRouteParams) (WorkerRouteResponse, error) { + if rc.Level != ZoneRouteLevel { + return WorkerRouteResponse{}, fmt.Errorf(errInvalidResourceContainerAccess, ZoneRouteLevel) + } + + if rc.Identifier == "" { + return WorkerRouteResponse{}, ErrMissingIdentifier + } + + uri := fmt.Sprintf("/zones/%s/workers/routes", rc.Identifier) + res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params) + if err != nil { + return WorkerRouteResponse{}, err + } + + var r WorkerRouteResponse + err = json.Unmarshal(res, &r) + if err != nil { + return WorkerRouteResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + return r, nil +} + +// DeleteWorkerRoute deletes worker route for a zone +// +// API reference: https://api.cloudflare.com/#worker-routes-delete-route +func (api *API) DeleteWorkerRoute(ctx context.Context, rc *ResourceContainer, routeID string) (WorkerRouteResponse, error) { + if rc.Level != ZoneRouteLevel { + return WorkerRouteResponse{}, fmt.Errorf(errInvalidResourceContainerAccess, ZoneRouteLevel) + } + + if rc.Identifier == "" { + return WorkerRouteResponse{}, ErrMissingIdentifier + } + + if routeID == "" { + return WorkerRouteResponse{}, errors.New("missing required route ID") + } + + uri := fmt.Sprintf("/zones/%s/workers/routes/%s", rc.Identifier, routeID) + res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil) + if err != nil { + return WorkerRouteResponse{}, err + } + var r WorkerRouteResponse + err = json.Unmarshal(res, &r) + if err != nil { + return WorkerRouteResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + return r, nil +} + +// ListWorkerRoutes returns list of Worker routes +// +// API reference: https://api.cloudflare.com/#worker-routes-list-routes +func (api *API) ListWorkerRoutes(ctx context.Context, rc *ResourceContainer, params ListWorkerRoutesParams) (WorkerRoutesResponse, error) { + if rc.Level != ZoneRouteLevel { + return WorkerRoutesResponse{}, fmt.Errorf(errInvalidResourceContainerAccess, ZoneRouteLevel) + } + + if rc.Identifier == "" { + return WorkerRoutesResponse{}, ErrMissingIdentifier + } + + uri := fmt.Sprintf("/zones/%s/workers/routes", rc.Identifier) + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return WorkerRoutesResponse{}, err + } + var r WorkerRoutesResponse + err = json.Unmarshal(res, &r) + if err != nil { + return WorkerRoutesResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + + return r, nil +} + +// GetWorkerRoute returns a Workers route. +// +// API reference: https://api.cloudflare.com/#worker-routes-get-route +func (api *API) GetWorkerRoute(ctx context.Context, rc *ResourceContainer, routeID string) (WorkerRouteResponse, error) { + if rc.Level != ZoneRouteLevel { + return WorkerRouteResponse{}, fmt.Errorf(errInvalidResourceContainerAccess, ZoneRouteLevel) + } + + if rc.Identifier == "" { + return WorkerRouteResponse{}, ErrMissingIdentifier + } + + uri := fmt.Sprintf("/zones/%s/workers/routes/%s", rc.Identifier, routeID) + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return WorkerRouteResponse{}, err + } + var r WorkerRouteResponse + err = json.Unmarshal(res, &r) + if err != nil { + return WorkerRouteResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + return r, nil +} + +// UpdateWorkerRoute updates worker route for a zone. +// +// API reference: https://api.cloudflare.com/#worker-routes-update-route +func (api *API) UpdateWorkerRoute(ctx context.Context, rc *ResourceContainer, params UpdateWorkerRouteParams) (WorkerRouteResponse, error) { + if rc.Level != ZoneRouteLevel { + return WorkerRouteResponse{}, fmt.Errorf(errInvalidResourceContainerAccess, ZoneRouteLevel) + } + + if rc.Identifier == "" { + return WorkerRouteResponse{}, ErrMissingIdentifier + } + + uri := fmt.Sprintf("/zones/%s/workers/routes/%s", rc.Identifier, params.Script) + res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params) + if err != nil { + return WorkerRouteResponse{}, err + } + var r WorkerRouteResponse + err = json.Unmarshal(res, &r) + if err != nil { + return WorkerRouteResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + return r, nil +} diff --git a/workers_routes_test.go b/workers_routes_test.go new file mode 100644 index 000000000..7182c1571 --- /dev/null +++ b/workers_routes_test.go @@ -0,0 +1,348 @@ +package cloudflare + +// func TestWorkers_CreateWorkerRoute(t *testing.T) { +// setup() +// defer teardown() + +// mux.HandleFunc("/zones"+testAccountID+"/workers/filters", func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method) +// w.Header().Set("content-type", "application/json") +// fmt.Fprintf(w, createWorkerRouteResponse) //nolint +// }) +// route := WorkerRoute{Pattern: "app1.example.com/*", Enabled: true} +// res, err := client.CreateWorkerRoute(context.Background(), "foo", route) +// want := WorkerRouteResponse{successResponse, WorkerRoute{ID: "e7a57d8746e74ae49c25994dadb421b1"}} +// if assert.NoError(t, err) { +// assert.Equal(t, want, res) +// } +// } + +// func TestWorkers_CreateWorkerRouteEnt(t *testing.T) { +// setup() +// defer teardown() + +// mux.HandleFunc("/zones"+testAccountID+"/workers/routes", func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method) +// w.Header().Set("content-type", "application/json") +// fmt.Fprintf(w, createWorkerRouteResponse) //nolint +// }) +// route := WorkerRoute{Pattern: "app1.example.com/*", Script: "test_script"} +// res, err := client.CreateWorkerRoute(context.Background(), "foo", route) +// want := WorkerRouteResponse{successResponse, WorkerRoute{ID: "e7a57d8746e74ae49c25994dadb421b1"}} +// if assert.NoError(t, err) { +// assert.Equal(t, want, res) +// } +// } + +// func TestWorkers_CreateWorkerRouteSingleScriptWithAccount(t *testing.T) { +// setup() +// defer teardown() + +// mux.HandleFunc("/zones"+testAccountID+"/workers/filters", func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method) +// w.Header().Set("content-type", "application/json") +// fmt.Fprintf(w, createWorkerRouteResponse) //nolint +// }) +// route := WorkerRoute{Pattern: "app1.example.com/*", Enabled: true} +// res, err := client.CreateWorkerRoute(context.Background(), "foo", route) +// want := WorkerRouteResponse{successResponse, WorkerRoute{ID: "e7a57d8746e74ae49c25994dadb421b1"}} +// if assert.NoError(t, err) { +// assert.Equal(t, want, res) +// } +// } + +// func TestWorkers_CreateWorkerRouteErrorsWhenMixingSingleAndMultiScriptProperties(t *testing.T) { +// setup() +// defer teardown() + +// route := WorkerRoute{Pattern: "app1.example.com/*", Script: "test_script", Enabled: true} +// _, err := client.CreateWorkerRoute(context.Background(), "foo", route) +// assert.EqualError(t, err, "Only `Script` or `Enabled` may be specified for a WorkerRoute, not both") +// } + +// func TestWorkers_CreateWorkerRouteWithNoScript(t *testing.T) { +// setup() + +// mux.HandleFunc("/zones"+testAccountID+"/workers/routes", func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method) +// w.Header().Set("content-type", "application/json") +// fmt.Fprintf(w, createWorkerRouteResponse) //nolint +// }) + +// route := WorkerRoute{Pattern: "app1.example.com/*"} +// _, err := client.CreateWorkerRoute(context.Background(), "foo", route) +// assert.NoError(t, err) +// } + +// func TestWorkers_DeleteWorkerRoute(t *testing.T) { +// setup() +// defer teardown() + +// mux.HandleFunc("/zones"+testAccountID+"/workers/routes/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method) +// w.Header().Set("content-type", "application/json") +// fmt.Fprintf(w, deleteWorkerRouteResponseData) //nolint +// }) +// res, err := client.DeleteWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1") +// want := WorkerRouteResponse{successResponse, +// WorkerRoute{ +// ID: "e7a57d8746e74ae49c25994dadb421b1", +// }} +// if assert.NoError(t, err) { +// assert.Equal(t, want, res) +// } +// } + +// func TestWorkers_DeleteWorkerRouteEnt(t *testing.T) { +// setup() +// defer teardown() + +// mux.HandleFunc("/zones"+testAccountID+"/workers/routes/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method) +// w.Header().Set("content-type", "application/json") +// fmt.Fprintf(w, deleteWorkerRouteResponseData) //nolint +// }) +// res, err := client.DeleteWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1") +// want := WorkerRouteResponse{successResponse, +// WorkerRoute{ +// ID: "e7a57d8746e74ae49c25994dadb421b1", +// }} +// if assert.NoError(t, err) { +// assert.Equal(t, want, res) +// } +// } + +// func TestWorkers_ListWorkerRoutes(t *testing.T) { +// setup() +// defer teardown() + +// mux.HandleFunc("/zones"+testAccountID+"/workers/filters", func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) +// w.Header().Set("content-type", "application/json") +// fmt.Fprintf(w, listRouteResponseData) //nolint +// }) + +// res, err := client.ListWorkerRoutes(context.Background(), "foo") +// want := WorkerRoutesResponse{successResponse, +// []WorkerRoute{ +// {ID: "e7a57d8746e74ae49c25994dadb421b1", Pattern: "app1.example.com/*", Enabled: true}, +// {ID: "f8b68e9857f85bf59c25994dadb421b1", Pattern: "app2.example.com/*", Enabled: false}, +// }, +// } +// if assert.NoError(t, err) { +// assert.Equal(t, want, res) +// } +// } + +// func TestWorkers_ListWorkerRoutesEnt(t *testing.T) { +// setup() +// defer teardown() + +// mux.HandleFunc("/zones"+testAccountID+"/workers/routes", func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) +// w.Header().Set("content-type", "application/json") +// fmt.Fprintf(w, listRouteEntResponseData) //nolint +// }) + +// res, err := client.ListWorkerRoutes(context.Background(), "foo") +// want := WorkerRoutesResponse{successResponse, +// []WorkerRoute{ +// {ID: "e7a57d8746e74ae49c25994dadb421b1", Pattern: "app1.example.com/*", Script: "test_script_1", Enabled: true}, +// {ID: "f8b68e9857f85bf59c25994dadb421b1", Pattern: "app2.example.com/*", Script: "test_script_2", Enabled: true}, +// {ID: "2b5bf4240cd34c77852fac70b1bf745a", Pattern: "app3.example.com/*", Script: "", Enabled: false}, +// }, +// } +// if assert.NoError(t, err) { +// assert.Equal(t, want, res) +// } +// } + +// func TestWorkers_GetWorkerRoute(t *testing.T) { +// setup() +// defer teardown() + +// mux.HandleFunc("/zones"+testAccountID+"/workers/routes/1234", func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) +// w.Header().Set("content-type", "application/json") +// fmt.Fprintf(w, getRouteResponseData) //nolint +// }) + +// res, err := client.GetWorkerRoute(context.Background(), "foo", "1234") +// want := WorkerRouteResponse{successResponse, +// WorkerRoute{ +// ID: "e7a57d8746e74ae49c25994dadb421b1", +// Pattern: "app1.example.com/*", +// Script: "script-name"}, +// } +// if assert.NoError(t, err) { +// assert.Equal(t, want, res) +// } +// } + +// func TestWorkers_UpdateWorkerRoute(t *testing.T) { +// setup() +// defer teardown() + +// mux.HandleFunc("/zones"+testAccountID+"/workers/filters/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) +// w.Header().Set("content-type", "application/json") +// fmt.Fprintf(w, updateWorkerRouteResponse) //nolint +// }) +// route := WorkerRoute{Pattern: "app3.example.com/*", Enabled: true} +// res, err := client.UpdateWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1", route) +// want := WorkerRouteResponse{successResponse, +// WorkerRoute{ +// ID: "e7a57d8746e74ae49c25994dadb421b1", +// Pattern: "app3.example.com/*", +// Enabled: true, +// }} +// if assert.NoError(t, err) { +// assert.Equal(t, want, res) +// } +// } + +// func TestWorkers_UpdateWorkerRouteEnt(t *testing.T) { +// setup() +// defer teardown() + +// mux.HandleFunc("/zones"+testAccountID+"/workers/routes/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) +// w.Header().Set("content-type", "application/json") +// fmt.Fprintf(w, updateWorkerRouteEntResponse) //nolint +// }) +// route := WorkerRoute{Pattern: "app3.example.com/*", Script: "test_script_1"} +// res, err := client.UpdateWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1", route) +// want := WorkerRouteResponse{successResponse, +// WorkerRoute{ +// ID: "e7a57d8746e74ae49c25994dadb421b1", +// Pattern: "app3.example.com/*", +// Script: "test_script_1", +// }} +// if assert.NoError(t, err) { +// assert.Equal(t, want, res) +// } +// } + +// func TestWorkers_UpdateWorkerRouteSingleScriptWithAccount(t *testing.T) { +// setup() +// defer teardown() + +// mux.HandleFunc("/zones"+testAccountID+"/workers/filters/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) +// w.Header().Set("content-type", "application/json") +// fmt.Fprintf(w, updateWorkerRouteEntResponse) //nolint +// }) +// route := WorkerRoute{Pattern: "app3.example.com/*", Enabled: true} +// res, err := client.UpdateWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1", route) +// want := WorkerRouteResponse{successResponse, +// WorkerRoute{ +// ID: "e7a57d8746e74ae49c25994dadb421b1", +// Pattern: "app3.example.com/*", +// Script: "test_script_1", +// }} +// if assert.NoError(t, err) { +// assert.Equal(t, want, res) +// } +// } + +// func TestWorkers_ListWorkerBindingsMultiScript(t *testing.T) { +// setup() +// defer teardown() + +// mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/my-script/bindings", func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) +// w.Header().Set("content-type", "application/json") +// fmt.Fprintf(w, listBindingsResponseData) //nolint +// }) + +// mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/my-script/bindings/MY_WASM/content", func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) +// w.Header().Set("content-type", "application/wasm") +// _, _ = w.Write([]byte("mock multi-script wasm")) +// }) + +// res, err := client.ListWorkerBindings(context.Background(), &WorkerRequestParams{ +// ScriptName: "my-script", +// }) +// assert.NoError(t, err) + +// assert.Equal(t, successResponse, res.Response) +// assert.Equal(t, 7, len(res.BindingList)) + +// assert.Equal(t, res.BindingList[0], WorkerBindingListItem{ +// Name: "MY_KV", +// Binding: WorkerKvNamespaceBinding{ +// NamespaceID: "89f5f8fd93f94cb98473f6f421aa3b65", +// }, +// }) +// assert.Equal(t, WorkerKvNamespaceBindingType, res.BindingList[0].Binding.Type()) + +// assert.Equal(t, "MY_WASM", res.BindingList[1].Name) +// wasmBinding := res.BindingList[1].Binding.(WorkerWebAssemblyBinding) +// wasmModuleContent, err := io.ReadAll(wasmBinding.Module) +// assert.NoError(t, err) +// assert.Equal(t, []byte("mock multi-script wasm"), wasmModuleContent) +// assert.Equal(t, WorkerWebAssemblyBindingType, res.BindingList[1].Binding.Type()) + +// assert.Equal(t, res.BindingList[2], WorkerBindingListItem{ +// Name: "MY_PLAIN_TEXT", +// Binding: WorkerPlainTextBinding{ +// Text: "text", +// }, +// }) +// assert.Equal(t, WorkerPlainTextBindingType, res.BindingList[2].Binding.Type()) + +// assert.Equal(t, res.BindingList[3], WorkerBindingListItem{ +// Name: "MY_SECRET_TEXT", +// Binding: WorkerSecretTextBinding{}, +// }) +// assert.Equal(t, WorkerSecretTextBindingType, res.BindingList[3].Binding.Type()) + +// environment := "MY_ENVIRONMENT" +// assert.Equal(t, res.BindingList[4], WorkerBindingListItem{ +// Name: "MY_SERVICE_BINDING", +// Binding: WorkerServiceBinding{ +// Service: "MY_SERVICE", +// Environment: &environment, +// }, +// }) +// assert.Equal(t, WorkerServiceBindingType, res.BindingList[4].Binding.Type()) + +// assert.Equal(t, res.BindingList[5], WorkerBindingListItem{ +// Name: "MY_NEW_BINDING", +// Binding: WorkerInheritBinding{}, +// }) +// assert.Equal(t, WorkerInheritBindingType, res.BindingList[5].Binding.Type()) + +// assert.Equal(t, res.BindingList[6], WorkerBindingListItem{ +// Name: "MY_BUCKET", +// Binding: WorkerR2BucketBinding{ +// BucketName: "bucket", +// }, +// }) +// assert.Equal(t, WorkerR2BucketBindingType, res.BindingList[6].Binding.Type()) +// } + +// func TestWorkers_UpdateWorkerRouteErrorsWhenMixingSingleAndMultiScriptProperties(t *testing.T) { +// setup() +// defer teardown() + +// route := WorkerRoute{Pattern: "app1.example.com/*", Script: "test_script", Enabled: true} +// _, err := client.UpdateWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1", route) +// assert.EqualError(t, err, "Only `Script` or `Enabled` may be specified for a WorkerRoute, not both") +// } + +// func TestWorkers_UpdateWorkerRouteWithNoScript(t *testing.T) { +// setup() +// defer teardown() + +// mux.HandleFunc("/zones"+testAccountID+"/workers/routes/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) +// w.Header().Set("content-type", "application/json") +// fmt.Fprintf(w, updateWorkerRouteEntResponse) //nolint +// }) + +// route := WorkerRoute{Pattern: "app1.example.com/*"} +// _, err := client.UpdateWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1", route) +// assert.NoError(t, err) +// } diff --git a/workers_test.go b/workers_test.go index 1f5dbfbc0..d3a44d7f4 100644 --- a/workers_test.go +++ b/workers_test.go @@ -320,61 +320,30 @@ func parseMultipartUpload(r *http.Request) (multipartUpload, error) { }, nil } -func TestWorkers_DeleteWorker(t *testing.T) { +func TestDeleteWorker(t *testing.T) { setup() defer teardown() - mux.HandleFunc("/zones/foo/workers/script", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method) w.Header().Set("content-type", "application/javascript") - fmt.Fprintf(w, deleteWorkerResponseData) //nolint + fmt.Fprintf(w, deleteWorkerResponseData) }) - res, err := client.DeleteWorker(context.Background(), &WorkerRequestParams{ZoneID: "foo"}) - want := WorkerScriptResponse{ - Response: successResponse, - } - - if assert.NoError(t, err) { - assert.Equal(t, want.Response, res.Response) - } -} - -func TestWorkers_DeleteWorkerWithName(t *testing.T) { - setup(UsingAccount("foo")) - defer teardown() - - mux.HandleFunc("/accounts/foo/workers/scripts/bar", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method) - w.Header().Set("content-type", "application/javascript") - fmt.Fprintf(w, deleteWorkerResponseData) //nolint - }) - res, err := client.DeleteWorker(context.Background(), &WorkerRequestParams{ScriptName: "bar"}) - want := WorkerScriptResponse{ - Response: successResponse, - } - if assert.NoError(t, err) { - assert.Equal(t, want.Response, res.Response) - } -} -func TestWorkers_DeleteWorkerWithNameErrorsWithoutAccountId(t *testing.T) { - setup() - defer teardown() - - _, err := client.DeleteWorker(context.Background(), &WorkerRequestParams{ScriptName: "bar"}) - assert.Error(t, err) + err := client.DeleteWorker(context.Background(), AccountIdentifier(testAccountID), DeleteWorkerParams{ScriptName: "bar"}) + assert.NoError(t, err) } -func TestWorkers_DownloadWorker(t *testing.T) { +func TestGetWorker(t *testing.T) { setup() defer teardown() - mux.HandleFunc("/zones/foo/workers/script", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/foo", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) w.Header().Set("content-type", "application/javascript") - fmt.Fprintf(w, workerScript) //nolint + fmt.Fprintf(w, workerScript) }) - res, err := client.DownloadWorker(context.Background(), &WorkerRequestParams{ZoneID: "foo"}) + res, err := client.GetWorker(context.Background(), AccountIdentifier(testAccountID), "foo") want := WorkerScriptResponse{ successResponse, false, @@ -386,67 +355,41 @@ func TestWorkers_DownloadWorker(t *testing.T) { } } -func TestWorkers_DownloadWorkerWithName(t *testing.T) { - setup(UsingAccount("foo")) - defer teardown() - - mux.HandleFunc("/accounts/foo/workers/scripts/bar", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) - w.Header().Set("content-type", "application/javascript") - fmt.Fprintf(w, workerScript) //nolint - }) - res, err := client.DownloadWorker(context.Background(), &WorkerRequestParams{ScriptName: "bar"}) - want := WorkerScriptResponse{ - successResponse, - false, - WorkerScript{ - Script: workerScript, - }} - if assert.NoError(t, err) { - assert.Equal(t, want.Script, res.Script) - } -} - -func TestWorkers_DownloadWorkerWithNameErrorsWithoutAccountId(t *testing.T) { +func TestGetWorker_Module(t *testing.T) { setup() defer teardown() - _, err := client.DownloadWorker(context.Background(), &WorkerRequestParams{ScriptName: "bar"}) - assert.Error(t, err) -} - -func TestWorkers_DownloadWorkerModule(t *testing.T) { - setup(UsingAccount("foo")) - defer teardown() - - mux.HandleFunc("/accounts/foo/workers/scripts/bar", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/foo", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) w.Header().Set("content-type", "multipart/form-data; boundary=workermodulescriptdownload") - fmt.Fprintf(w, workerModuleScriptDownloadResponse) //nolint + fmt.Fprintf(w, workerModuleScriptDownloadResponse) }) - res, err := client.DownloadWorker(context.Background(), &WorkerRequestParams{ScriptName: "bar"}) + + res, err := client.GetWorker(context.Background(), AccountIdentifier(testAccountID), "foo") want := WorkerScriptResponse{ successResponse, true, WorkerScript{ Script: workerModuleScript, - }} + }, + } + if assert.NoError(t, err) { assert.Equal(t, want.Script, res.Script) } } -func TestWorkers_ListWorkerScripts(t *testing.T) { - setup(UsingAccount("foo")) +func TestListWorkers(t *testing.T) { + setup() defer teardown() - mux.HandleFunc("/accounts/foo/workers/scripts", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, listWorkersResponseData) //nolint + fmt.Fprintf(w, listWorkersResponseData) }) - res, err := client.ListWorkerScripts(context.Background()) + res, err := client.ListWorkers(context.Background(), AccountIdentifier(testAccountID), ListWorkersParams{}) sampleDate, _ := time.Parse(time.RFC3339Nano, "2018-04-22T17:10:48.938097Z") want := []WorkerMetaData{ { @@ -467,18 +410,18 @@ func TestWorkers_ListWorkerScripts(t *testing.T) { } } -func TestWorkers_UploadWorker(t *testing.T) { +func TestUploadWorker_Basic(t *testing.T) { setup() defer teardown() - mux.HandleFunc("/zones/foo/workers/script", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/foo", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) contentTypeHeader := r.Header.Get("content-type") assert.Equal(t, "application/javascript", contentTypeHeader, "Expected content-type request header to be 'application/javascript', got %s", contentTypeHeader) w.Header().Set("content-type", "application/json") fmt.Fprintf(w, uploadWorkerResponseData) //nolint }) - res, err := client.UploadWorker(context.Background(), &WorkerRequestParams{ZoneID: "foo"}, &WorkerScriptParams{Script: workerScript}) + res, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{Name: "foo", Script: workerScript}) formattedTime, _ := time.Parse(time.RFC3339Nano, "2018-06-09T15:17:01.989141Z") want := WorkerScriptResponse{ successResponse, @@ -496,11 +439,11 @@ func TestWorkers_UploadWorker(t *testing.T) { } } -func TestWorkers_UploadWorkerAsModule(t *testing.T) { +func TestUploadWorker_Module(t *testing.T) { setup() defer teardown() - mux.HandleFunc("/zones/foo/workers/script", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/foo", func(w http.ResponseWriter, r *http.Request) { mpUpload, err := parseMultipartUpload(r) assert.NoError(t, err) @@ -515,9 +458,9 @@ func TestWorkers_UploadWorkerAsModule(t *testing.T) { assert.Equal(t, expectedContentType, contentTypeHeader, "Expected content-type request header to be %s, got %s", expectedContentType, contentTypeHeader) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, uploadWorkerModuleResponseData) //nolint + fmt.Fprintf(w, uploadWorkerModuleResponseData) }) - res, err := client.UploadWorker(context.Background(), &WorkerRequestParams{ZoneID: "foo"}, &WorkerScriptParams{Script: workerModuleScript, Module: true}) + res, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{Name: "foo", Script: workerModuleScript, Module: true}) formattedTime, _ := time.Parse(time.RFC3339Nano, "2018-06-09T15:17:01.989141Z") want := WorkerScriptResponse{ successResponse, @@ -535,76 +478,10 @@ func TestWorkers_UploadWorkerAsModule(t *testing.T) { } } -func TestWorkers_UploadWorkerWithName(t *testing.T) { - setup(UsingAccount("foo")) - defer teardown() - - mux.HandleFunc("/accounts/foo/workers/scripts/bar", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) - contentTypeHeader := r.Header.Get("content-type") - assert.Equal(t, "application/javascript", contentTypeHeader, "Expected content-type request header to be 'application/javascript', got %s", contentTypeHeader) - w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, uploadWorkerResponseData) //nolint - }) - res, err := client.UploadWorker(context.Background(), &WorkerRequestParams{ScriptName: "bar"}, &WorkerScriptParams{Script: workerScript}) - formattedTime, _ := time.Parse(time.RFC3339Nano, "2018-06-09T15:17:01.989141Z") - want := WorkerScriptResponse{ - successResponse, - false, - WorkerScript{ - Script: workerScript, - WorkerMetaData: WorkerMetaData{ - ETAG: "279cf40d86d70b82f6cd3ba90a646b3ad995912da446836d7371c21c6a43977a", - Size: 191, - ModifiedOn: formattedTime, - }, - }} - if assert.NoError(t, err) { - assert.Equal(t, want, res) - } -} - -func TestWorkers_UploadWorkerSingleScriptWithAccount(t *testing.T) { - setup(UsingAccount("foo")) - defer teardown() - - mux.HandleFunc("/zones/foo/workers/script", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) - contentTypeHeader := r.Header.Get("content-type") - assert.Equal(t, "application/javascript", contentTypeHeader, "Expected content-type request header to be 'application/javascript', got %s", contentTypeHeader) - w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, uploadWorkerResponseData) //nolint - }) - res, err := client.UploadWorker(context.Background(), &WorkerRequestParams{ZoneID: "foo"}, &WorkerScriptParams{Script: workerScript}) - formattedTime, _ := time.Parse(time.RFC3339Nano, "2018-06-09T15:17:01.989141Z") - want := WorkerScriptResponse{ - successResponse, - false, - WorkerScript{ - Script: workerScript, - WorkerMetaData: WorkerMetaData{ - ETAG: "279cf40d86d70b82f6cd3ba90a646b3ad995912da446836d7371c21c6a43977a", - Size: 191, - ModifiedOn: formattedTime, - }, - }} - if assert.NoError(t, err) { - assert.Equal(t, want, res) - } -} - -func TestWorkers_UploadWorkerWithNameErrorsWithoutAccountId(t *testing.T) { +func TestUploadWorker_WithDurableObjectBinding(t *testing.T) { setup() defer teardown() - _, err := client.UploadWorker(context.Background(), &WorkerRequestParams{ScriptName: "bar"}, &WorkerScriptParams{Script: workerScript}) - assert.Error(t, err) -} - -func TestWorkers_UploadWorkerWithDurableObjectBinding(t *testing.T) { - setup(UsingAccount("foo")) - defer teardown() - handler := func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) @@ -623,11 +500,13 @@ func TestWorkers_UploadWorkerWithDurableObjectBinding(t *testing.T) { assert.Equal(t, expectedBindings, mpUpload.BindingMeta) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, uploadWorkerResponseData) //nolint + fmt.Fprintf(w, uploadWorkerResponseData) } - mux.HandleFunc("/accounts/foo/workers/scripts/bar", handler) - scriptParams := WorkerScriptParams{ + mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", handler) + + _, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ + Name: "bar", Script: workerScript, Bindings: map[string]WorkerBinding{ "b1": WorkerDurableObjectBinding{ @@ -635,13 +514,13 @@ func TestWorkers_UploadWorkerWithDurableObjectBinding(t *testing.T) { ScriptName: "the_script", }, }, - } - _, err := client.UploadWorkerWithBindings(context.Background(), &WorkerRequestParams{ScriptName: "bar"}, &scriptParams) + }) + assert.NoError(t, err) } -func TestWorkers_UploadWorkerWithInheritBinding(t *testing.T) { - setup(UsingAccount("foo")) +func TestUploadWorker_WithInheritBinding(t *testing.T) { + setup() defer teardown() // Setup route handler for both single-script and multi-script @@ -666,22 +545,10 @@ func TestWorkers_UploadWorkerWithInheritBinding(t *testing.T) { assert.Equal(t, expectedBindings, mpUpload.BindingMeta) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, uploadWorkerResponseData) //nolint + fmt.Fprintf(w, uploadWorkerResponseData) } - mux.HandleFunc("/zones/foo/workers/script", handler) - mux.HandleFunc("/accounts/foo/workers/scripts/bar", handler) + mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", handler) - scriptParams := WorkerScriptParams{ - Script: workerScript, - Bindings: map[string]WorkerBinding{ - "b1": WorkerInheritBinding{}, - "b2": WorkerInheritBinding{ - OldName: "old_binding_name", - }, - }, - } - - // Expected response formattedTime, _ := time.Parse(time.RFC3339Nano, "2018-06-09T15:17:01.989141Z") want := WorkerScriptResponse{ successResponse, @@ -695,21 +562,22 @@ func TestWorkers_UploadWorkerWithInheritBinding(t *testing.T) { }, }} - // Test single-script - res, err := client.UploadWorkerWithBindings(context.Background(), &WorkerRequestParams{ZoneID: "foo"}, &scriptParams) - if assert.NoError(t, err) { - assert.Equal(t, want, res) - } - - // Test multi-script - res, err = client.UploadWorkerWithBindings(context.Background(), &WorkerRequestParams{ScriptName: "bar"}, &scriptParams) + res, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ + Name: "bar", + Script: workerScript, + Bindings: map[string]WorkerBinding{ + "b1": WorkerInheritBinding{}, + "b2": WorkerInheritBinding{ + OldName: "old_binding_name", + }, + }}) if assert.NoError(t, err) { assert.Equal(t, want, res) } } -func TestWorkers_UploadWorkerWithKVBinding(t *testing.T) { - setup(UsingAccount("foo")) +func TestUploadWorker_WithKVBinding(t *testing.T) { + setup() defer teardown() handler := func(w http.ResponseWriter, r *http.Request) { @@ -729,24 +597,23 @@ func TestWorkers_UploadWorkerWithKVBinding(t *testing.T) { assert.Equal(t, expectedBindings, mpUpload.BindingMeta) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, uploadWorkerResponseData) //nolint + fmt.Fprintf(w, uploadWorkerResponseData) } - mux.HandleFunc("/accounts/foo/workers/scripts/bar", handler) + mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", handler) - scriptParams := WorkerScriptParams{ + _, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ + Name: "bar", Script: workerScript, Bindings: map[string]WorkerBinding{ "b1": WorkerKvNamespaceBinding{ NamespaceID: "test-namespace", }, - }, - } - _, err := client.UploadWorkerWithBindings(context.Background(), &WorkerRequestParams{ScriptName: "bar"}, &scriptParams) + }}) assert.NoError(t, err) } -func TestWorkers_UploadWorkerWithWasmBinding(t *testing.T) { - setup(UsingAccount("foo")) +func TestUploadWorker_WithWasmBinding(t *testing.T) { + setup() defer teardown() handler := func(w http.ResponseWriter, r *http.Request) { @@ -771,24 +638,25 @@ func TestWorkers_UploadWorkerWithWasmBinding(t *testing.T) { assert.Equal(t, []byte("fake-wasm"), wasmContent) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, uploadWorkerResponseData) //nolint + fmt.Fprintf(w, uploadWorkerResponseData) } - mux.HandleFunc("/accounts/foo/workers/scripts/bar", handler) + mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", handler) - scriptParams := WorkerScriptParams{ + _, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ + Name: "bar", Script: workerScript, Bindings: map[string]WorkerBinding{ "b1": WorkerWebAssemblyBinding{ Module: strings.NewReader("fake-wasm"), }, }, - } - _, err := client.UploadWorkerWithBindings(context.Background(), &WorkerRequestParams{ScriptName: "bar"}, &scriptParams) + }) + assert.NoError(t, err) } -func TestWorkers_UploadWorkerWithPlainTextBinding(t *testing.T) { - setup(UsingAccount("foo")) +func TestUploadWorker_WithPlainTextBinding(t *testing.T) { + setup() defer teardown() handler := func(w http.ResponseWriter, r *http.Request) { @@ -810,25 +678,26 @@ func TestWorkers_UploadWorkerWithPlainTextBinding(t *testing.T) { w.Header().Set("content-type", "application/json") fmt.Fprintf(w, uploadWorkerResponseData) //nolint } - mux.HandleFunc("/accounts/foo/workers/scripts/bar", handler) + mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", handler) - scriptParams := WorkerScriptParams{ + _, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ + Name: "bar", Script: workerScript, Bindings: map[string]WorkerBinding{ "b1": WorkerPlainTextBinding{ Text: "plain text value", }, }, - } - _, err := client.UploadWorkerWithBindings(context.Background(), &WorkerRequestParams{ScriptName: "bar"}, &scriptParams) + }) + assert.NoError(t, err) } -func TestWorkers_UploadWorkerAsModuleWithPlainTextBinding(t *testing.T) { - setup(UsingAccount("foo")) +func TestUploadWorker_ModuleWithPlainTextBinding(t *testing.T) { + setup() defer teardown() - mux.HandleFunc("/accounts/foo/workers/scripts/bar", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) mpUpload, err := parseMultipartUpload(r) @@ -856,7 +725,8 @@ func TestWorkers_UploadWorkerAsModuleWithPlainTextBinding(t *testing.T) { fmt.Fprintf(w, uploadWorkerModuleResponseData) //nolint }) - scriptParams := WorkerScriptParams{ + _, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ + Name: "bar", Script: workerModuleScript, Module: true, Bindings: map[string]WorkerBinding{ @@ -864,13 +734,13 @@ func TestWorkers_UploadWorkerAsModuleWithPlainTextBinding(t *testing.T) { Text: "plain text value", }, }, - } - _, err := client.UploadWorkerWithBindings(context.Background(), &WorkerRequestParams{ScriptName: "bar"}, &scriptParams) + }) + assert.NoError(t, err) } -func TestWorkers_UploadWorkerWithSecretTextBinding(t *testing.T) { - setup(UsingAccount("foo")) +func TestUploadWorker_WithSecretTextBinding(t *testing.T) { + setup() defer teardown() handler := func(w http.ResponseWriter, r *http.Request) { @@ -892,22 +762,22 @@ func TestWorkers_UploadWorkerWithSecretTextBinding(t *testing.T) { w.Header().Set("content-type", "application/json") fmt.Fprintf(w, uploadWorkerResponseData) //nolint } - mux.HandleFunc("/accounts/foo/workers/scripts/bar", handler) + mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", handler) - scriptParams := WorkerScriptParams{ + _, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ + Name: "bar", Script: workerScript, Bindings: map[string]WorkerBinding{ "b1": WorkerSecretTextBinding{ Text: "secret text value", }, }, - } - _, err := client.UploadWorkerWithBindings(context.Background(), &WorkerRequestParams{ScriptName: "bar"}, &scriptParams) + }) assert.NoError(t, err) } -func TestWorkers_UploadWorkerWithServiceBinding(t *testing.T) { - setup(UsingAccount("foo")) +func TestUploadWorker_WithServiceBinding(t *testing.T) { + setup() defer teardown() handler := func(w http.ResponseWriter, r *http.Request) { @@ -935,10 +805,10 @@ func TestWorkers_UploadWorkerWithServiceBinding(t *testing.T) { w.Header().Set("content-type", "application/json") fmt.Fprintf(w, uploadWorkerResponseData) //nolint } - mux.HandleFunc("/accounts/foo/workers/scripts/bar", handler) + mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", handler) - environment := "the_environment" - scriptParams := WorkerScriptParams{ + _, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ + Name: "bar", Script: workerScript, Bindings: map[string]WorkerBinding{ "b1": WorkerServiceBinding{ @@ -946,394 +816,9 @@ func TestWorkers_UploadWorkerWithServiceBinding(t *testing.T) { }, "b2": WorkerServiceBinding{ Service: "the_service", - Environment: &environment, + Environment: StringPtr("the_environment"), }, }, - } - _, err := client.UploadWorkerWithBindings(context.Background(), &WorkerRequestParams{ScriptName: "bar"}, &scriptParams) - assert.NoError(t, err) -} - -func TestWorkers_CreateWorkerRoute(t *testing.T) { - setup() - defer teardown() - - mux.HandleFunc("/zones/foo/workers/filters", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method) - w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, createWorkerRouteResponse) //nolint - }) - route := WorkerRoute{Pattern: "app1.example.com/*", Enabled: true} - res, err := client.CreateWorkerRoute(context.Background(), "foo", route) - want := WorkerRouteResponse{successResponse, WorkerRoute{ID: "e7a57d8746e74ae49c25994dadb421b1"}} - if assert.NoError(t, err) { - assert.Equal(t, want, res) - } -} - -func TestWorkers_CreateWorkerRouteEnt(t *testing.T) { - setup(UsingAccount("foo")) - defer teardown() - - mux.HandleFunc("/zones/foo/workers/routes", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method) - w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, createWorkerRouteResponse) //nolint - }) - route := WorkerRoute{Pattern: "app1.example.com/*", Script: "test_script"} - res, err := client.CreateWorkerRoute(context.Background(), "foo", route) - want := WorkerRouteResponse{successResponse, WorkerRoute{ID: "e7a57d8746e74ae49c25994dadb421b1"}} - if assert.NoError(t, err) { - assert.Equal(t, want, res) - } -} - -func TestWorkers_CreateWorkerRouteSingleScriptWithAccount(t *testing.T) { - setup(UsingAccount("foo")) - defer teardown() - - mux.HandleFunc("/zones/foo/workers/filters", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method) - w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, createWorkerRouteResponse) //nolint - }) - route := WorkerRoute{Pattern: "app1.example.com/*", Enabled: true} - res, err := client.CreateWorkerRoute(context.Background(), "foo", route) - want := WorkerRouteResponse{successResponse, WorkerRoute{ID: "e7a57d8746e74ae49c25994dadb421b1"}} - if assert.NoError(t, err) { - assert.Equal(t, want, res) - } -} - -func TestWorkers_CreateWorkerRouteErrorsWhenMixingSingleAndMultiScriptProperties(t *testing.T) { - setup(UsingAccount("foo")) - defer teardown() - - route := WorkerRoute{Pattern: "app1.example.com/*", Script: "test_script", Enabled: true} - _, err := client.CreateWorkerRoute(context.Background(), "foo", route) - assert.EqualError(t, err, "Only `Script` or `Enabled` may be specified for a WorkerRoute, not both") -} - -func TestWorkers_CreateWorkerRouteWithNoScript(t *testing.T) { - setup(UsingAccount("foo")) - - mux.HandleFunc("/zones/foo/workers/routes", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method) - w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, createWorkerRouteResponse) //nolint - }) - - route := WorkerRoute{Pattern: "app1.example.com/*"} - _, err := client.CreateWorkerRoute(context.Background(), "foo", route) - assert.NoError(t, err) -} - -func TestWorkers_DeleteWorkerRoute(t *testing.T) { - setup() - defer teardown() - - mux.HandleFunc("/zones/foo/workers/routes/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method) - w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, deleteWorkerRouteResponseData) //nolint - }) - res, err := client.DeleteWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1") - want := WorkerRouteResponse{successResponse, - WorkerRoute{ - ID: "e7a57d8746e74ae49c25994dadb421b1", - }} - if assert.NoError(t, err) { - assert.Equal(t, want, res) - } -} - -func TestWorkers_DeleteWorkerRouteEnt(t *testing.T) { - setup(UsingAccount("foo")) - defer teardown() - - mux.HandleFunc("/zones/foo/workers/routes/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method) - w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, deleteWorkerRouteResponseData) //nolint - }) - res, err := client.DeleteWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1") - want := WorkerRouteResponse{successResponse, - WorkerRoute{ - ID: "e7a57d8746e74ae49c25994dadb421b1", - }} - if assert.NoError(t, err) { - assert.Equal(t, want, res) - } -} - -func TestWorkers_ListWorkerRoutes(t *testing.T) { - setup() - defer teardown() - - mux.HandleFunc("/zones/foo/workers/filters", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) - w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, listRouteResponseData) //nolint - }) - - res, err := client.ListWorkerRoutes(context.Background(), "foo") - want := WorkerRoutesResponse{successResponse, - []WorkerRoute{ - {ID: "e7a57d8746e74ae49c25994dadb421b1", Pattern: "app1.example.com/*", Enabled: true}, - {ID: "f8b68e9857f85bf59c25994dadb421b1", Pattern: "app2.example.com/*", Enabled: false}, - }, - } - if assert.NoError(t, err) { - assert.Equal(t, want, res) - } -} - -func TestWorkers_ListWorkerRoutesEnt(t *testing.T) { - setup(UsingAccount("foo")) - defer teardown() - - mux.HandleFunc("/zones/foo/workers/routes", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) - w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, listRouteEntResponseData) //nolint - }) - - res, err := client.ListWorkerRoutes(context.Background(), "foo") - want := WorkerRoutesResponse{successResponse, - []WorkerRoute{ - {ID: "e7a57d8746e74ae49c25994dadb421b1", Pattern: "app1.example.com/*", Script: "test_script_1", Enabled: true}, - {ID: "f8b68e9857f85bf59c25994dadb421b1", Pattern: "app2.example.com/*", Script: "test_script_2", Enabled: true}, - {ID: "2b5bf4240cd34c77852fac70b1bf745a", Pattern: "app3.example.com/*", Script: "", Enabled: false}, - }, - } - if assert.NoError(t, err) { - assert.Equal(t, want, res) - } -} - -func TestWorkers_GetWorkerRoute(t *testing.T) { - setup() - defer teardown() - - mux.HandleFunc("/zones/foo/workers/routes/1234", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) - w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, getRouteResponseData) //nolint - }) - - res, err := client.GetWorkerRoute(context.Background(), "foo", "1234") - want := WorkerRouteResponse{successResponse, - WorkerRoute{ - ID: "e7a57d8746e74ae49c25994dadb421b1", - Pattern: "app1.example.com/*", - Script: "script-name"}, - } - if assert.NoError(t, err) { - assert.Equal(t, want, res) - } -} - -func TestWorkers_UpdateWorkerRoute(t *testing.T) { - setup() - defer teardown() - - mux.HandleFunc("/zones/foo/workers/filters/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) - w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, updateWorkerRouteResponse) //nolint - }) - route := WorkerRoute{Pattern: "app3.example.com/*", Enabled: true} - res, err := client.UpdateWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1", route) - want := WorkerRouteResponse{successResponse, - WorkerRoute{ - ID: "e7a57d8746e74ae49c25994dadb421b1", - Pattern: "app3.example.com/*", - Enabled: true, - }} - if assert.NoError(t, err) { - assert.Equal(t, want, res) - } -} - -func TestWorkers_UpdateWorkerRouteEnt(t *testing.T) { - setup(UsingAccount("foo")) - defer teardown() - - mux.HandleFunc("/zones/foo/workers/routes/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) - w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, updateWorkerRouteEntResponse) //nolint - }) - route := WorkerRoute{Pattern: "app3.example.com/*", Script: "test_script_1"} - res, err := client.UpdateWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1", route) - want := WorkerRouteResponse{successResponse, - WorkerRoute{ - ID: "e7a57d8746e74ae49c25994dadb421b1", - Pattern: "app3.example.com/*", - Script: "test_script_1", - }} - if assert.NoError(t, err) { - assert.Equal(t, want, res) - } -} - -func TestWorkers_UpdateWorkerRouteSingleScriptWithAccount(t *testing.T) { - setup(UsingAccount("foo")) - defer teardown() - - mux.HandleFunc("/zones/foo/workers/filters/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) - w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, updateWorkerRouteEntResponse) //nolint - }) - route := WorkerRoute{Pattern: "app3.example.com/*", Enabled: true} - res, err := client.UpdateWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1", route) - want := WorkerRouteResponse{successResponse, - WorkerRoute{ - ID: "e7a57d8746e74ae49c25994dadb421b1", - Pattern: "app3.example.com/*", - Script: "test_script_1", - }} - if assert.NoError(t, err) { - assert.Equal(t, want, res) - } -} - -func TestWorkers_ListWorkerBindingsMultiScript(t *testing.T) { - setup(UsingAccount("foo")) - defer teardown() - - mux.HandleFunc("/accounts/foo/workers/scripts/my-script/bindings", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) - w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, listBindingsResponseData) //nolint - }) - - mux.HandleFunc("/accounts/foo/workers/scripts/my-script/bindings/MY_WASM/content", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) - w.Header().Set("content-type", "application/wasm") - _, _ = w.Write([]byte("mock multi-script wasm")) - }) - - res, err := client.ListWorkerBindings(context.Background(), &WorkerRequestParams{ - ScriptName: "my-script", - }) - assert.NoError(t, err) - - assert.Equal(t, successResponse, res.Response) - assert.Equal(t, 8, len(res.BindingList)) - - assert.Equal(t, res.BindingList[0], WorkerBindingListItem{ - Name: "MY_KV", - Binding: WorkerKvNamespaceBinding{ - NamespaceID: "89f5f8fd93f94cb98473f6f421aa3b65", - }, }) - assert.Equal(t, WorkerKvNamespaceBindingType, res.BindingList[0].Binding.Type()) - - assert.Equal(t, "MY_WASM", res.BindingList[1].Name) - wasmBinding := res.BindingList[1].Binding.(WorkerWebAssemblyBinding) - wasmModuleContent, err := io.ReadAll(wasmBinding.Module) assert.NoError(t, err) - assert.Equal(t, []byte("mock multi-script wasm"), wasmModuleContent) - assert.Equal(t, WorkerWebAssemblyBindingType, res.BindingList[1].Binding.Type()) - - assert.Equal(t, res.BindingList[2], WorkerBindingListItem{ - Name: "MY_PLAIN_TEXT", - Binding: WorkerPlainTextBinding{ - Text: "text", - }, - }) - assert.Equal(t, WorkerPlainTextBindingType, res.BindingList[2].Binding.Type()) - - assert.Equal(t, res.BindingList[3], WorkerBindingListItem{ - Name: "MY_SECRET_TEXT", - Binding: WorkerSecretTextBinding{}, - }) - assert.Equal(t, WorkerSecretTextBindingType, res.BindingList[3].Binding.Type()) - - environment := "MY_ENVIRONMENT" - assert.Equal(t, res.BindingList[4], WorkerBindingListItem{ - Name: "MY_SERVICE_BINDING", - Binding: WorkerServiceBinding{ - Service: "MY_SERVICE", - Environment: &environment, - }, - }) - assert.Equal(t, WorkerServiceBindingType, res.BindingList[4].Binding.Type()) - - assert.Equal(t, res.BindingList[5], WorkerBindingListItem{ - Name: "MY_NEW_BINDING", - Binding: WorkerInheritBinding{}, - }) - assert.Equal(t, WorkerInheritBindingType, res.BindingList[5].Binding.Type()) - - assert.Equal(t, res.BindingList[6], WorkerBindingListItem{ - Name: "MY_BUCKET", - Binding: WorkerR2BucketBinding{ - BucketName: "bucket", - }, - }) - assert.Equal(t, WorkerR2BucketBindingType, res.BindingList[6].Binding.Type()) - - assert.Equal(t, res.BindingList[7], WorkerBindingListItem{ - Name: "MY_DATASET", - Binding: WorkerAnalyticsEngineBinding{ - Dataset: "my_dataset", - }, - }) - assert.Equal(t, WorkerAnalyticsEngineBindingType, res.BindingList[7].Binding.Type()) -} - -func TestWorkers_UpdateWorkerRouteErrorsWhenMixingSingleAndMultiScriptProperties(t *testing.T) { - setup(UsingAccount("foo")) - defer teardown() - - route := WorkerRoute{Pattern: "app1.example.com/*", Script: "test_script", Enabled: true} - _, err := client.UpdateWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1", route) - assert.EqualError(t, err, "Only `Script` or `Enabled` may be specified for a WorkerRoute, not both") -} - -func TestWorkers_UpdateWorkerRouteWithNoScript(t *testing.T) { - setup(UsingAccount("foo")) - defer teardown() - - mux.HandleFunc("/zones/foo/workers/routes/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) - w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, updateWorkerRouteEntResponse) //nolint - }) - - route := WorkerRoute{Pattern: "app1.example.com/*"} - _, err := client.UpdateWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1", route) - assert.NoError(t, err) -} - -func TestWorkers_AttachWorkerToDomain(t *testing.T) { - setup(UsingAccount(testAccountID)) - defer teardown() - - mux.HandleFunc("/accounts/"+testAccountID+"/workers/domains", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) - w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, attachWorkerToDomainResponse) //nolint - }) - res, err := client.AttachWorkerToDomain(context.Background(), AccountIdentifier(testAccountID), &WorkerDomainParams{ - ZoneID: testZoneID, - Hostname: "app4.example.com", - Service: "test_script_1", - Environment: "production", - }) - want := WorkerDomainResponse{ - successResponse, - WorkerDomainResult{ - ID: "e7a57d8746e74ae49c25994dadb421b1", - ZoneID: testZoneID, - Service: "test_script_1", - Hostname: "api4.example.com", - Environment: "production", - }} - if assert.NoError(t, err) { - assert.Equal(t, want.Response, res.Response) - } } From 8b05a9db49126304e2a0f89ab9df402e029771f5 Mon Sep 17 00:00:00 2001 From: Jacob Bednarz Date: Wed, 30 Nov 2022 14:57:21 +1100 Subject: [PATCH 2/6] workers: modernise all method signatures and conventions Updates all the available Workers endpoints to follow the new method signatures and conventions for calling the API. --- workers_bindings_test.go | 97 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 workers_bindings_test.go diff --git a/workers_bindings_test.go b/workers_bindings_test.go new file mode 100644 index 000000000..a21aec341 --- /dev/null +++ b/workers_bindings_test.go @@ -0,0 +1,97 @@ +package cloudflare + +import ( + "context" + "fmt" + "io" + "net/http" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestListWorkerBindings(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/my-script/bindings", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) + w.Header().Set("content-type", "application/json") + fmt.Fprintf(w, listBindingsResponseData) + }) + + mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/my-script/bindings/MY_WASM/content", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) + w.Header().Set("content-type", "application/wasm") + _, _ = w.Write([]byte("mock multi-script wasm")) + }) + + res, err := client.ListWorkerBindings(context.Background(), AccountIdentifier(testAccountID), ListWorkerBindingsParams{ + ScriptName: "my-script", + }) + assert.NoError(t, err) + + assert.Equal(t, successResponse, res.Response) + assert.Equal(t, 8, len(res.BindingList)) + + assert.Equal(t, res.BindingList[0], WorkerBindingListItem{ + Name: "MY_KV", + Binding: WorkerKvNamespaceBinding{ + NamespaceID: "89f5f8fd93f94cb98473f6f421aa3b65", + }, + }) + assert.Equal(t, WorkerKvNamespaceBindingType, res.BindingList[0].Binding.Type()) + + assert.Equal(t, "MY_WASM", res.BindingList[1].Name) + wasmBinding := res.BindingList[1].Binding.(WorkerWebAssemblyBinding) + wasmModuleContent, err := io.ReadAll(wasmBinding.Module) + assert.NoError(t, err) + assert.Equal(t, []byte("mock multi-script wasm"), wasmModuleContent) + assert.Equal(t, WorkerWebAssemblyBindingType, res.BindingList[1].Binding.Type()) + + assert.Equal(t, res.BindingList[2], WorkerBindingListItem{ + Name: "MY_PLAIN_TEXT", + Binding: WorkerPlainTextBinding{ + Text: "text", + }, + }) + assert.Equal(t, WorkerPlainTextBindingType, res.BindingList[2].Binding.Type()) + + assert.Equal(t, res.BindingList[3], WorkerBindingListItem{ + Name: "MY_SECRET_TEXT", + Binding: WorkerSecretTextBinding{}, + }) + assert.Equal(t, WorkerSecretTextBindingType, res.BindingList[3].Binding.Type()) + + environment := "MY_ENVIRONMENT" + assert.Equal(t, res.BindingList[4], WorkerBindingListItem{ + Name: "MY_SERVICE_BINDING", + Binding: WorkerServiceBinding{ + Service: "MY_SERVICE", + Environment: &environment, + }, + }) + assert.Equal(t, WorkerServiceBindingType, res.BindingList[4].Binding.Type()) + + assert.Equal(t, res.BindingList[5], WorkerBindingListItem{ + Name: "MY_NEW_BINDING", + Binding: WorkerInheritBinding{}, + }) + assert.Equal(t, WorkerInheritBindingType, res.BindingList[5].Binding.Type()) + + assert.Equal(t, res.BindingList[6], WorkerBindingListItem{ + Name: "MY_BUCKET", + Binding: WorkerR2BucketBinding{ + BucketName: "bucket", + }, + }) + assert.Equal(t, WorkerR2BucketBindingType, res.BindingList[6].Binding.Type()) + + assert.Equal(t, res.BindingList[7], WorkerBindingListItem{ + Name: "MY_DATASET", + Binding: WorkerAnalyticsEngineBinding{ + Dataset: "my_dataset", + }, + }) + assert.Equal(t, WorkerAnalyticsEngineBindingType, res.BindingList[7].Binding.Type()) +} From 1c2393c43a33e4268d1e43ec624db5dba5862464 Mon Sep 17 00:00:00 2001 From: Jacob Bednarz Date: Wed, 30 Nov 2022 14:57:21 +1100 Subject: [PATCH 3/6] workers: modernise all method signatures and conventions Updates all the available Workers endpoints to follow the new method signatures and conventions for calling the API. --- errors.go | 5 +- workers.go | 78 +++--- workers_account_settings.go | 8 + workers_bindings.go | 43 ++-- workers_cron_triggers.go | 35 ++- workers_cron_triggers_test.go | 8 +- workers_domains.go | 48 ---- workers_example_test.go | 198 --------------- workers_kv.go | 68 +++++ workers_routes.go | 9 +- workers_routes_test.go | 465 +++++++++------------------------- workers_secrets.go | 52 +++- workers_secrets_test.go | 24 +- workers_tail.go | 1 + workers_test.go | 45 ++-- 15 files changed, 384 insertions(+), 703 deletions(-) delete mode 100644 workers_domains.go delete mode 100644 workers_example_test.go diff --git a/errors.go b/errors.go index 994707978..723c18bae 100644 --- a/errors.go +++ b/errors.go @@ -29,7 +29,8 @@ const ( errAPIKeysAndTokensAreMutuallyExclusive = "API keys and tokens are mutually exclusive" //nolint:gosec errMissingCredentials = "no credentials provided" - errInvalidResourceContainerAccess = "requested resource container (%q) is not supported for this endpoint" + errInvalidResourceContainerAccess = "requested resource container (%q) is not supported for this endpoint" + errRequiredAccountLevelResourceContainer = "this endpoint requires using an account level resource container and identifiers" ) var ( @@ -40,6 +41,8 @@ var ( ErrAccountIDOrZoneIDAreRequired = errors.New(errMissingAccountOrZoneID) ErrAccountIDAndZoneIDAreMutuallyExclusive = errors.New(errAccountIDAndZoneIDAreMutuallyExclusive) ErrMissingResourceIdentifier = errors.New(errMissingResourceIdentifier) + + ErrRequiredAccountLevelResourceContainer = errors.New(errRequiredAccountLevelResourceContainer) ) type ErrorType string diff --git a/workers.go b/workers.go index b762acad8..ae2bf7c5d 100644 --- a/workers.go +++ b/workers.go @@ -21,8 +21,8 @@ type WorkerRequestParams struct { } type CreateWorkerParams struct { - Name string - Script string + ScriptName string + Script string // Module changes the Content-Type header to specify the script is an // ES Module syntax script. @@ -35,7 +35,7 @@ type CreateWorkerParams struct { // WorkerScriptParams provides a worker script and the associated bindings. type WorkerScriptParams struct { - Script string + ScriptName string // Module changes the Content-Type header to specify the script is an // ES Module syntax script. @@ -50,8 +50,9 @@ type WorkerScriptParams struct { // // API reference: https://api.cloudflare.com/#worker-routes-properties type WorkerRoute struct { - Pattern string `json:"pattern"` - Script string `json:"script,omitempty"` + ID string `json:"id,omitempty"` + Pattern string `json:"pattern"` + ScriptName string `json:"script,omitempty"` } // WorkerRoutesResponse embeds Response struct and slice of WorkerRoutes. @@ -85,6 +86,7 @@ type WorkerMetaData struct { // WorkerListResponse wrapper struct for API response to worker script list API call. type WorkerListResponse struct { Response + ResultInfo WorkerList []WorkerMetaData `json:"result"` } @@ -105,6 +107,14 @@ type DeleteWorkerParams struct { // // API reference: https://api.cloudflare.com/#worker-script-delete-worker func (api *API) DeleteWorker(ctx context.Context, rc *ResourceContainer, params DeleteWorkerParams) error { + if rc.Level != AccountRouteLevel { + return ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return ErrMissingAccountID + } + uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s", rc.Identifier, params.ScriptName) res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil) @@ -127,11 +137,11 @@ func (api *API) DeleteWorker(ctx context.Context, rc *ResourceContainer, params // API reference: https://developers.cloudflare.com/workers/tooling/api/scripts/ func (api *API) GetWorker(ctx context.Context, rc *ResourceContainer, scriptName string) (WorkerScriptResponse, error) { if rc.Level != AccountRouteLevel { - return WorkerScriptResponse{}, fmt.Errorf(errInvalidResourceContainerAccess, ZoneRouteLevel) + return WorkerScriptResponse{}, ErrRequiredAccountLevelResourceContainer } if rc.Identifier == "" { - return WorkerScriptResponse{}, ErrMissingIdentifier + return WorkerScriptResponse{}, ErrMissingAccountID } uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s", rc.Identifier, scriptName) @@ -168,30 +178,42 @@ func (api *API) GetWorker(ctx context.Context, rc *ResourceContainer, scriptName // ListWorkers returns list of Workers for given account. // // API reference: https://developers.cloudflare.com/workers/tooling/api/scripts/ -func (api *API) ListWorkers(ctx context.Context, rc *ResourceContainer, params ListWorkersParams) (WorkerListResponse, error) { +func (api *API) ListWorkers(ctx context.Context, rc *ResourceContainer, params ListWorkersParams) (WorkerListResponse, *ResultInfo, error) { + if rc.Level != AccountRouteLevel { + return WorkerListResponse{}, &ResultInfo{}, ErrRequiredAccountLevelResourceContainer + } + if rc.Identifier == "" { - return WorkerListResponse{}, ErrMissingAccountID + return WorkerListResponse{}, &ResultInfo{}, ErrMissingAccountID } uri := fmt.Sprintf("/accounts/%s/workers/scripts", rc.Identifier) res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) if err != nil { - return WorkerListResponse{}, err + return WorkerListResponse{}, &ResultInfo{}, err } var r WorkerListResponse err = json.Unmarshal(res, &r) if err != nil { - return WorkerListResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + return WorkerListResponse{}, &ResultInfo{}, fmt.Errorf("%s: %w", errUnmarshalError, err) } - return r, nil + return r, &r.ResultInfo, nil } // UploadWorker pushes raw script content for your Worker. // // API reference: https://api.cloudflare.com/#worker-script-upload-worker func (api *API) UploadWorker(ctx context.Context, rc *ResourceContainer, params CreateWorkerParams) (WorkerScriptResponse, error) { + if rc.Level != AccountRouteLevel { + return WorkerScriptResponse{}, ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return WorkerScriptResponse{}, ErrMissingAccountID + } + var ( contentType = "application/javascript" err error @@ -205,37 +227,7 @@ func (api *API) UploadWorker(ctx context.Context, rc *ResourceContainer, params } } - if rc.Level == AccountRouteLevel { - return api.uploadWorkerWithName(ctx, rc, params.Name, contentType, []byte(body)) - } else { - return api.uploadWorkerForZone(ctx, rc, contentType, []byte(body)) - } -} - -func (api *API) uploadWorkerForZone(ctx context.Context, rc *ResourceContainer, contentType string, body []byte) (WorkerScriptResponse, error) { - uri := fmt.Sprintf("/zones/%s/workers/script", rc.Identifier) - headers := make(http.Header) - headers.Set("Content-Type", contentType) - - res, err := api.makeRequestContextWithHeaders(ctx, http.MethodPut, uri, body, headers) - var r WorkerScriptResponse - if err != nil { - return r, err - } - - err = json.Unmarshal(res, &r) - if err != nil { - return r, fmt.Errorf("%s: %w", errUnmarshalError, err) - } - - return r, nil -} - -func (api *API) uploadWorkerWithName(ctx context.Context, rc *ResourceContainer, scriptName, contentType string, body []byte) (WorkerScriptResponse, error) { - if rc.Identifier == "" { - return WorkerScriptResponse{}, ErrMissingAccountID - } - uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s", rc.Identifier, scriptName) + uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s", rc.Identifier, params.ScriptName) headers := make(http.Header) headers.Set("Content-Type", contentType) res, err := api.makeRequestContextWithHeaders(ctx, http.MethodPut, uri, body, headers) diff --git a/workers_account_settings.go b/workers_account_settings.go index d8e58516a..6b3b65d6d 100644 --- a/workers_account_settings.go +++ b/workers_account_settings.go @@ -37,6 +37,10 @@ func (api *API) CreateWorkersAccountSettings(ctx context.Context, rc *ResourceCo return WorkersAccountSettings{}, ErrMissingAccountID } + if rc.Level != AccountRouteLevel { + return WorkersAccountSettings{}, ErrRequiredAccountLevelResourceContainer + } + uri := fmt.Sprintf("/accounts/%s/workers/account-settings", rc.Identifier) res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params) if err != nil { @@ -59,6 +63,10 @@ func (api *API) WorkersAccountSettings(ctx context.Context, rc *ResourceContaine return WorkersAccountSettings{}, ErrMissingAccountID } + if rc.Level != AccountRouteLevel { + return WorkersAccountSettings{}, ErrRequiredAccountLevelResourceContainer + } + uri := fmt.Sprintf("/accounts/%s/workers/account-settings", rc.Identifier) res, err := api.makeRequestContext(ctx, http.MethodGet, uri, params) if err != nil { diff --git a/workers_bindings.go b/workers_bindings.go index 7ba01a451..d2ac3ee96 100644 --- a/workers_bindings.go +++ b/workers_bindings.go @@ -41,6 +41,10 @@ const ( WorkerAnalyticsEngineBindingType WorkerBindingType = "analytics_engine" ) +type ListWorkerBindingsParams struct { + ScriptName string +} + // WorkerBindingListItem a struct representing an individual binding in a list of bindings. type WorkerBindingListItem struct { Name string `json:"name"` @@ -314,15 +318,20 @@ func getRandomPartName() string { } // ListWorkerBindings returns all the bindings for a particular worker. -func (api *API) ListWorkerBindings(ctx context.Context, requestParams *WorkerRequestParams) (WorkerBindingListResponse, error) { - if requestParams.ScriptName == "" { +func (api *API) ListWorkerBindings(ctx context.Context, rc *ResourceContainer, params ListWorkerBindingsParams) (WorkerBindingListResponse, error) { + if params.ScriptName == "" { return WorkerBindingListResponse{}, errors.New("ScriptName is required") } - if api.AccountID == "" { - return WorkerBindingListResponse{}, errors.New("account ID required") + + if rc.Level != AccountRouteLevel { + return WorkerBindingListResponse{}, ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return WorkerBindingListResponse{}, ErrMissingAccountID } - uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s/bindings", api.AccountID, requestParams.ScriptName) + uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s/bindings", rc.Identifier, params.ScriptName) var jsonRes struct { Response @@ -371,10 +380,11 @@ func (api *API) ListWorkerBindings(ctx context.Context, requestParams *WorkerReq case WorkerWebAssemblyBindingType: bindingListItem.Binding = WorkerWebAssemblyBinding{ Module: &bindingContentReader{ - ctx: ctx, - api: api, - requestParams: requestParams, - bindingName: name, + api: api, + ctx: ctx, + accountID: rc.Identifier, + params: ¶ms, + bindingName: name, }, } case WorkerPlainTextBindingType: @@ -415,18 +425,19 @@ func (api *API) ListWorkerBindings(ctx context.Context, requestParams *WorkerReq // is first called. This is only useful for binding types // that store raw bytes, like WebAssembly modules. type bindingContentReader struct { - api *API - requestParams *WorkerRequestParams - ctx context.Context - bindingName string - content []byte - position int + api *API + accountID string + params *ListWorkerBindingsParams + ctx context.Context + bindingName string + content []byte + position int } func (b *bindingContentReader) Read(p []byte) (n int, err error) { // Lazily load the content when Read() is first called if b.content == nil { - uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s/bindings/%s/content", b.api.AccountID, b.requestParams.ScriptName, b.bindingName) + uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s/bindings/%s/content", b.accountID, b.params.ScriptName, b.bindingName) res, err := b.api.makeRequestContext(b.ctx, http.MethodGet, uri, nil) if err != nil { return 0, err diff --git a/workers_cron_triggers.go b/workers_cron_triggers.go index 8938862ae..2322a5d68 100644 --- a/workers_cron_triggers.go +++ b/workers_cron_triggers.go @@ -27,12 +27,29 @@ type WorkerCronTrigger struct { ModifiedOn *time.Time `json:"modified_on,omitempty"` } +type ListWorkerCronTriggersParams struct { + ScriptName string +} + +type UpdateWorkerCronTriggersParams struct { + ScriptName string + Crons []WorkerCronTrigger +} + // ListWorkerCronTriggers fetches all available cron triggers for a single Worker // script. // // API reference: https://api.cloudflare.com/#worker-cron-trigger-get-cron-triggers -func (api *API) ListWorkerCronTriggers(ctx context.Context, accountID, scriptName string) ([]WorkerCronTrigger, error) { - uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s/schedules", accountID, scriptName) +func (api *API) ListWorkerCronTriggers(ctx context.Context, rc *ResourceContainer, params ListWorkerCronTriggersParams) ([]WorkerCronTrigger, error) { + if rc.Level != AccountRouteLevel { + return []WorkerCronTrigger{}, ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return []WorkerCronTrigger{}, ErrMissingIdentifier + } + + uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s/schedules", rc.Identifier, params.ScriptName) res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) if err != nil { return []WorkerCronTrigger{}, err @@ -49,9 +66,17 @@ func (api *API) ListWorkerCronTriggers(ctx context.Context, accountID, scriptNam // UpdateWorkerCronTriggers updates a single schedule for a Worker cron trigger. // // API reference: https://api.cloudflare.com/#worker-cron-trigger-update-cron-triggers -func (api *API) UpdateWorkerCronTriggers(ctx context.Context, accountID, scriptName string, crons []WorkerCronTrigger) ([]WorkerCronTrigger, error) { - uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s/schedules", accountID, scriptName) - res, err := api.makeRequestContext(ctx, http.MethodPut, uri, crons) +func (api *API) UpdateWorkerCronTriggers(ctx context.Context, rc *ResourceContainer, params UpdateWorkerCronTriggersParams) ([]WorkerCronTrigger, error) { + if rc.Level != AccountRouteLevel { + return []WorkerCronTrigger{}, ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return []WorkerCronTrigger{}, ErrMissingIdentifier + } + + uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s/schedules", rc.Identifier, params.ScriptName) + res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params.Crons) if err != nil { return []WorkerCronTrigger{}, err } diff --git a/workers_cron_triggers_test.go b/workers_cron_triggers_test.go index d2acba1e2..0194d75ef 100644 --- a/workers_cron_triggers_test.go +++ b/workers_cron_triggers_test.go @@ -11,7 +11,7 @@ import ( ) func TestListWorkerCronTriggers(t *testing.T) { - setup(UsingAccount("9a7806061c88ada191ed06f989cc3dac")) + setup() defer teardown() handler := func(w http.ResponseWriter, r *http.Request) { @@ -42,14 +42,14 @@ func TestListWorkerCronTriggers(t *testing.T) { CreatedOn: &createdOn, }} - actual, err := client.ListWorkerCronTriggers(context.Background(), testAccountID, "example-script") + actual, err := client.ListWorkerCronTriggers(context.Background(), AccountIdentifier(testAccountID), ListWorkerCronTriggersParams{ScriptName: "example-script"}) if assert.NoError(t, err) { assert.Equal(t, want, actual) } } func TestUpdateWorkerCronTriggers(t *testing.T) { - setup(UsingAccount("9a7806061c88ada191ed06f989cc3dac")) + setup() defer teardown() handler := func(w http.ResponseWriter, r *http.Request) { @@ -80,7 +80,7 @@ func TestUpdateWorkerCronTriggers(t *testing.T) { CreatedOn: &createdOn, }} - actual, err := client.UpdateWorkerCronTriggers(context.Background(), testAccountID, "example-script", want) + actual, err := client.UpdateWorkerCronTriggers(context.Background(), AccountIdentifier(testAccountID), UpdateWorkerCronTriggersParams{ScriptName: "example-script", Crons: want}) if assert.NoError(t, err) { assert.Equal(t, want, actual) } diff --git a/workers_domains.go b/workers_domains.go deleted file mode 100644 index e8caea979..000000000 --- a/workers_domains.go +++ /dev/null @@ -1,48 +0,0 @@ -package cloudflare - -import ( - "context" - "encoding/json" - "fmt" - "net/http" -) - -type WorkerDomainParams struct { - ZoneID string `json:"zone_id"` - Hostname string `json:"hostname"` - Service string `json:"service"` - Environment string `json:"environment,omitempty"` -} - -type WorkerDomainResult struct { - ID string `json:"id"` - ZoneID string `json:"zone_id"` - ZoneName string `json:"zone_name"` - Hostname string `json:"hostname"` - Service string `json:"service"` - Environment string `json:"environment"` -} - -type WorkerDomainResponse struct { - Response - WorkerDomainResult `json:"result"` -} - -// AttachWorkerToDomain attaches a worker to a zone and hostname -// -// API reference: https://api.cloudflare.com/#worker-domain-attach-to-domain -func (api *API) AttachWorkerToDomain(ctx context.Context, rc *ResourceContainer, params *WorkerDomainParams) (WorkerDomainResponse, error) { - uri := fmt.Sprintf("/accounts/%s/workers/domains", rc.Identifier) - res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params) - if err != nil { - return WorkerDomainResponse{}, err - } - - var r WorkerDomainResponse - err = json.Unmarshal(res, &r) - if err != nil { - return WorkerDomainResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err) - } - - return r, nil -} diff --git a/workers_example_test.go b/workers_example_test.go deleted file mode 100644 index f70c7b93a..000000000 --- a/workers_example_test.go +++ /dev/null @@ -1,198 +0,0 @@ -package cloudflare_test - -// var ( -// workerScript = "addEventListener('fetch', event => {\n event.passThroughOnException()\nevent.respondWith(handleRequest(event.request))\n})\n\nasync function handleRequest(request) {\n return fetch(request)\n}" -// ) - -// func ExampleAPI_UploadWorker() { -// api, err := cloudflare.New(apiKey, user) -// if err != nil { -// log.Fatal(err) -// } - -// zoneID, err := api.ZoneIDByName(domain) -// if err != nil { -// log.Fatal(err) -// } - -// res, err := api.UploadWorker(context.Background(), &cloudflare.WorkerRequestParams{ZoneID: zoneID}, &cloudflare.WorkerScriptParams{Script: workerScript}) -// if err != nil { -// log.Fatal(err) -// } -// fmt.Printf("%+v", res) - -// UploadWorkerWithName() -// } - -// func UploadWorkerWithName() { -// api, err := cloudflare.New(apiKey, user, cloudflare.UsingAccount("foo")) -// if err != nil { -// log.Fatal(err) -// } - -// res, err := api.UploadWorker(context.Background(), &cloudflare.WorkerRequestParams{ScriptName: "baz"}, &cloudflare.WorkerScriptParams{Script: workerScript}) -// if err != nil { -// log.Fatal(err) -// } -// fmt.Printf("%+v", res) -// } - -// func ExampleAPI_DownloadWorker() { -// api, err := cloudflare.New(apiKey, user) -// if err != nil { -// log.Fatal(err) -// } - -// zoneID, err := api.ZoneIDByName(domain) -// if err != nil { -// log.Fatal(err) -// } - -// res, err := api.DownloadWorker(context.Background(), &cloudflare.WorkerRequestParams{ZoneID: zoneID}) -// if err != nil { -// log.Fatal(err) -// } -// fmt.Printf("%+v", res) - -// DownloadWorkerWithName() -// } - -// func DownloadWorkerWithName() { -// api, err := cloudflare.New(apiKey, user, cloudflare.UsingAccount("foo")) -// if err != nil { -// log.Fatal(err) -// } - -// res, err := api.DownloadWorker(context.Background(), &cloudflare.WorkerRequestParams{ScriptName: "baz"}) -// if err != nil { -// log.Fatal(err) -// } -// fmt.Printf("%+v", res) -// } - -// func ExampleAPI_DeleteWorker() { -// api, err := cloudflare.New(apiKey, user) -// if err != nil { -// log.Fatal(err) -// } - -// zoneID, err := api.ZoneIDByName(domain) -// if err != nil { -// log.Fatal(err) -// } -// res, err := api.DeleteWorker(context.Background(), &cloudflare.WorkerRequestParams{ZoneID: zoneID}) -// if err != nil { -// log.Fatal(err) -// } -// fmt.Printf("%+v", res) - -// DeleteWorkerWithName() -// } - -// func DeleteWorkerWithName() { -// api, err := cloudflare.New(apiKey, user, cloudflare.UsingAccount("foo")) -// if err != nil { -// log.Fatal(err) -// } - -// res, err := api.DeleteWorker(context.Background(), &cloudflare.WorkerRequestParams{ScriptName: "baz"}) -// if err != nil { -// log.Fatal(err) -// } -// fmt.Printf("%+v", res) -// } - -// func ExampleAPI_ListWorkerScripts() { -// api, err := cloudflare.New(apiKey, user, cloudflare.UsingAccount("foo")) -// if err != nil { -// log.Fatal(err) -// } - -// res, err := api.ListWorkerScripts(context.Background()) -// if err != nil { -// log.Fatal(err) -// } -// fmt.Printf("%+v", res.WorkerList) -// } - -// func ExampleAPI_CreateWorkerRoute() { -// api, err := cloudflare.New(apiKey, user) -// if err != nil { -// log.Fatal(err) -// } - -// zoneID, err := api.ZoneIDByName(domain) -// if err != nil { -// log.Fatal(err) -// } -// route := cloudflare.WorkerRoute{Pattern: "app1.example.com/*", Enabled: true} -// res, err := api.CreateWorkerRoute(context.Background(), zoneID, route) -// if err != nil { -// log.Fatal(err) -// } -// fmt.Printf("%+v", res) -// } - -// func ExampleAPI_UpdateWorkerRoute() { -// api, err := cloudflare.New(apiKey, user) -// if err != nil { -// log.Fatal(err) -// } - -// zoneID, err := api.ZoneIDByName(domain) -// if err != nil { -// log.Fatal(err) -// } -// // pull from existing list of routes to perform update on -// routesResponse, err := api.ListWorkerRoutes(context.Background(), zoneID) -// if err != nil { -// log.Fatal(err) -// } -// route := cloudflare.WorkerRoute{Pattern: "app2.example.com/*", Enabled: true} -// // update first route retrieved from the listWorkerRoutes call with details above -// res, err := api.UpdateWorkerRoute(context.Background(), zoneID, routesResponse.Routes[0].ID, route) -// if err != nil { -// log.Fatal(err) -// } -// fmt.Printf("%+v", res) -// } - -// func ExampleAPI_ListWorkerRoutes() { -// api, err := cloudflare.New(apiKey, user) -// if err != nil { -// log.Fatal(err) -// } - -// zoneID, err := api.ZoneIDByName(domain) -// if err != nil { -// log.Fatal(err) -// } -// res, err := api.ListWorkerRoutes(context.Background(), zoneID) -// if err != nil { -// log.Fatal(err) -// } -// fmt.Printf("%+v", res) -// } - -// func ExampleAPI_DeleteWorkerRoute() { -// api, err := cloudflare.New(apiKey, user) -// if err != nil { -// log.Fatal(err) -// } - -// zoneID, err := api.ZoneIDByName(domain) -// if err != nil { -// log.Fatal(err) -// } -// // pull from existing list of routes to perform delete on -// routesResponse, err := api.ListWorkerRoutes(context.Background(), zoneID) -// if err != nil { -// log.Fatal(err) -// } -// // delete first route retrieved from the listWorkerRoutes call -// res, err := api.DeleteWorkerRoute(context.Background(), zoneID, routesResponse.Routes[0].ID) -// if err != nil { -// log.Fatal(err) -// } -// fmt.Printf("%+v", res) -// } diff --git a/workers_kv.go b/workers_kv.go index f7a01bc06..7cdf30e3c 100644 --- a/workers_kv.go +++ b/workers_kv.go @@ -106,6 +106,13 @@ type ListWorkersKVsParams struct { // // API reference: https://api.cloudflare.com/#workers-kv-namespace-create-a-namespace func (api *API) CreateWorkersKVNamespace(ctx context.Context, rc *ResourceContainer, params CreateWorkersKVNamespaceParams) (WorkersKVNamespaceResponse, error) { + if rc.Level != AccountRouteLevel { + return WorkersKVNamespaceResponse{}, ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return WorkersKVNamespaceResponse{}, ErrMissingIdentifier + } uri := fmt.Sprintf("/accounts/%s/storage/kv/namespaces", rc.Identifier) res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params) if err != nil { @@ -124,6 +131,14 @@ func (api *API) CreateWorkersKVNamespace(ctx context.Context, rc *ResourceContai // // API reference: https://api.cloudflare.com/#workers-kv-namespace-list-namespaces func (api *API) ListWorkersKVNamespaces(ctx context.Context, rc *ResourceContainer, params ListWorkersKVNamespacesParams) ([]WorkersKVNamespace, *ResultInfo, error) { + if rc.Level != AccountRouteLevel { + return []WorkersKVNamespace{}, &ResultInfo{}, ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return []WorkersKVNamespace{}, &ResultInfo{}, ErrMissingIdentifier + } + autoPaginate := true if params.PerPage >= 1 || params.Page >= 1 { autoPaginate = false @@ -183,6 +198,14 @@ func (api *API) DeleteWorkersKVNamespace(ctx context.Context, rc *ResourceContai // // API reference: https://api.cloudflare.com/#workers-kv-namespace-rename-a-namespace func (api *API) UpdateWorkersKVNamespace(ctx context.Context, rc *ResourceContainer, params UpdateWorkersKVNamespaceParams) (Response, error) { + if rc.Level != AccountRouteLevel { + return Response{}, ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return Response{}, ErrMissingIdentifier + } + uri := fmt.Sprintf("/accounts/%s/storage/kv/namespaces/%s", rc.Identifier, params.NamespaceID) res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params) if err != nil { @@ -201,6 +224,14 @@ func (api *API) UpdateWorkersKVNamespace(ctx context.Context, rc *ResourceContai // // API reference: https://api.cloudflare.com/#workers-kv-namespace-write-key-value-pair func (api *API) WriteWorkersKVEntry(ctx context.Context, rc *ResourceContainer, params WriteWorkersKVEntryParams) (Response, error) { + if rc.Level != AccountRouteLevel { + return Response{}, ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return Response{}, ErrMissingIdentifier + } + uri := fmt.Sprintf("/accounts/%s/storage/kv/namespaces/%s/values/%s", rc.Identifier, params.NamespaceID, url.PathEscape(params.Key)) res, err := api.makeRequestContextWithHeaders( ctx, http.MethodPut, uri, params.Value, http.Header{"Content-Type": []string{"application/octet-stream"}}, @@ -221,6 +252,14 @@ func (api *API) WriteWorkersKVEntry(ctx context.Context, rc *ResourceContainer, // // API reference: https://api.cloudflare.com/#workers-kv-namespace-write-multiple-key-value-pairs func (api *API) WriteWorkersKVEntries(ctx context.Context, rc *ResourceContainer, params WriteWorkersKVEntriesParams) (Response, error) { + if rc.Level != AccountRouteLevel { + return Response{}, ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return Response{}, ErrMissingIdentifier + } + uri := fmt.Sprintf("/accounts/%s/storage/kv/namespaces/%s/bulk", rc.Identifier, params.NamespaceID) res, err := api.makeRequestContextWithHeaders( ctx, http.MethodPut, uri, params.KVs, http.Header{"Content-Type": []string{"application/json"}}, @@ -242,6 +281,13 @@ func (api *API) WriteWorkersKVEntries(ctx context.Context, rc *ResourceContainer // // API reference: https://api.cloudflare.com/#workers-kv-namespace-read-key-value-pair func (api API) GetWorkersKV(ctx context.Context, rc *ResourceContainer, params GetWorkersKVParams) ([]byte, error) { + if rc.Level != AccountRouteLevel { + return []byte(``), ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return []byte(``), ErrMissingIdentifier + } uri := fmt.Sprintf("/accounts/%s/storage/kv/namespaces/%s/values/%s", rc.Identifier, params.NamespaceID, url.PathEscape(params.Key)) res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) if err != nil { @@ -254,6 +300,13 @@ func (api API) GetWorkersKV(ctx context.Context, rc *ResourceContainer, params G // // API reference: https://api.cloudflare.com/#workers-kv-namespace-delete-key-value-pair func (api API) DeleteWorkersKVEntry(ctx context.Context, rc *ResourceContainer, params DeleteWorkersKVEntryParams) (Response, error) { + if rc.Level != AccountRouteLevel { + return Response{}, ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return Response{}, ErrMissingIdentifier + } uri := fmt.Sprintf("/accounts/%s/storage/kv/namespaces/%s/values/%s", rc.Identifier, params.NamespaceID, url.PathEscape(params.Key)) res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil) if err != nil { @@ -271,6 +324,13 @@ func (api API) DeleteWorkersKVEntry(ctx context.Context, rc *ResourceContainer, // // API reference: https://api.cloudflare.com/#workers-kv-namespace-delete-multiple-key-value-pairs func (api *API) DeleteWorkersKVEntries(ctx context.Context, rc *ResourceContainer, params DeleteWorkersKVEntriesParams) (Response, error) { + if rc.Level != AccountRouteLevel { + return Response{}, ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return Response{}, ErrMissingIdentifier + } uri := fmt.Sprintf("/accounts/%s/storage/kv/namespaces/%s/bulk", rc.Identifier, params.NamespaceID) res, err := api.makeRequestContextWithHeaders( ctx, http.MethodDelete, uri, params.Keys, http.Header{"Content-Type": []string{"application/json"}}, @@ -291,6 +351,14 @@ func (api *API) DeleteWorkersKVEntries(ctx context.Context, rc *ResourceContaine // // API Reference: https://api.cloudflare.com/#workers-kv-namespace-list-a-namespace-s-keys func (api API) ListWorkersKVKeys(ctx context.Context, rc *ResourceContainer, params ListWorkersKVsParams) (ListStorageKeysResponse, error) { + if rc.Level != AccountRouteLevel { + return ListStorageKeysResponse{}, ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return ListStorageKeysResponse{}, ErrMissingIdentifier + } + uri := buildURI( fmt.Sprintf("/accounts/%s/storage/kv/namespaces/%s/keys", rc.Identifier, params.NamespaceID), params, diff --git a/workers_routes.go b/workers_routes.go index 31ec7937b..ec43d9e8b 100644 --- a/workers_routes.go +++ b/workers_routes.go @@ -8,6 +8,8 @@ import ( "net/http" ) +var ErrMissingWorkerRouteID = errors.New("missing required route ID") + type ListWorkerRoutes struct{} type CreateWorkerRouteParams struct { @@ -18,6 +20,7 @@ type CreateWorkerRouteParams struct { type ListWorkerRoutesParams struct{} type UpdateWorkerRouteParams struct { + ID string `json:"id,omitempty"` Pattern string `json:"pattern"` Script string `json:"script,omitempty"` } @@ -140,7 +143,11 @@ func (api *API) UpdateWorkerRoute(ctx context.Context, rc *ResourceContainer, pa return WorkerRouteResponse{}, ErrMissingIdentifier } - uri := fmt.Sprintf("/zones/%s/workers/routes/%s", rc.Identifier, params.Script) + if params.ID == "" { + return WorkerRouteResponse{}, ErrMissingWorkerRouteID + } + + uri := fmt.Sprintf("/zones/%s/workers/routes/%s", rc.Identifier, params.ID) res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params) if err != nil { return WorkerRouteResponse{}, err diff --git a/workers_routes_test.go b/workers_routes_test.go index 7182c1571..f0070a913 100644 --- a/workers_routes_test.go +++ b/workers_routes_test.go @@ -1,348 +1,121 @@ package cloudflare -// func TestWorkers_CreateWorkerRoute(t *testing.T) { -// setup() -// defer teardown() - -// mux.HandleFunc("/zones"+testAccountID+"/workers/filters", func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method) -// w.Header().Set("content-type", "application/json") -// fmt.Fprintf(w, createWorkerRouteResponse) //nolint -// }) -// route := WorkerRoute{Pattern: "app1.example.com/*", Enabled: true} -// res, err := client.CreateWorkerRoute(context.Background(), "foo", route) -// want := WorkerRouteResponse{successResponse, WorkerRoute{ID: "e7a57d8746e74ae49c25994dadb421b1"}} -// if assert.NoError(t, err) { -// assert.Equal(t, want, res) -// } -// } - -// func TestWorkers_CreateWorkerRouteEnt(t *testing.T) { -// setup() -// defer teardown() - -// mux.HandleFunc("/zones"+testAccountID+"/workers/routes", func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method) -// w.Header().Set("content-type", "application/json") -// fmt.Fprintf(w, createWorkerRouteResponse) //nolint -// }) -// route := WorkerRoute{Pattern: "app1.example.com/*", Script: "test_script"} -// res, err := client.CreateWorkerRoute(context.Background(), "foo", route) -// want := WorkerRouteResponse{successResponse, WorkerRoute{ID: "e7a57d8746e74ae49c25994dadb421b1"}} -// if assert.NoError(t, err) { -// assert.Equal(t, want, res) -// } -// } - -// func TestWorkers_CreateWorkerRouteSingleScriptWithAccount(t *testing.T) { -// setup() -// defer teardown() - -// mux.HandleFunc("/zones"+testAccountID+"/workers/filters", func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method) -// w.Header().Set("content-type", "application/json") -// fmt.Fprintf(w, createWorkerRouteResponse) //nolint -// }) -// route := WorkerRoute{Pattern: "app1.example.com/*", Enabled: true} -// res, err := client.CreateWorkerRoute(context.Background(), "foo", route) -// want := WorkerRouteResponse{successResponse, WorkerRoute{ID: "e7a57d8746e74ae49c25994dadb421b1"}} -// if assert.NoError(t, err) { -// assert.Equal(t, want, res) -// } -// } - -// func TestWorkers_CreateWorkerRouteErrorsWhenMixingSingleAndMultiScriptProperties(t *testing.T) { -// setup() -// defer teardown() - -// route := WorkerRoute{Pattern: "app1.example.com/*", Script: "test_script", Enabled: true} -// _, err := client.CreateWorkerRoute(context.Background(), "foo", route) -// assert.EqualError(t, err, "Only `Script` or `Enabled` may be specified for a WorkerRoute, not both") -// } - -// func TestWorkers_CreateWorkerRouteWithNoScript(t *testing.T) { -// setup() - -// mux.HandleFunc("/zones"+testAccountID+"/workers/routes", func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method) -// w.Header().Set("content-type", "application/json") -// fmt.Fprintf(w, createWorkerRouteResponse) //nolint -// }) - -// route := WorkerRoute{Pattern: "app1.example.com/*"} -// _, err := client.CreateWorkerRoute(context.Background(), "foo", route) -// assert.NoError(t, err) -// } - -// func TestWorkers_DeleteWorkerRoute(t *testing.T) { -// setup() -// defer teardown() - -// mux.HandleFunc("/zones"+testAccountID+"/workers/routes/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method) -// w.Header().Set("content-type", "application/json") -// fmt.Fprintf(w, deleteWorkerRouteResponseData) //nolint -// }) -// res, err := client.DeleteWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1") -// want := WorkerRouteResponse{successResponse, -// WorkerRoute{ -// ID: "e7a57d8746e74ae49c25994dadb421b1", -// }} -// if assert.NoError(t, err) { -// assert.Equal(t, want, res) -// } -// } - -// func TestWorkers_DeleteWorkerRouteEnt(t *testing.T) { -// setup() -// defer teardown() - -// mux.HandleFunc("/zones"+testAccountID+"/workers/routes/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method) -// w.Header().Set("content-type", "application/json") -// fmt.Fprintf(w, deleteWorkerRouteResponseData) //nolint -// }) -// res, err := client.DeleteWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1") -// want := WorkerRouteResponse{successResponse, -// WorkerRoute{ -// ID: "e7a57d8746e74ae49c25994dadb421b1", -// }} -// if assert.NoError(t, err) { -// assert.Equal(t, want, res) -// } -// } - -// func TestWorkers_ListWorkerRoutes(t *testing.T) { -// setup() -// defer teardown() - -// mux.HandleFunc("/zones"+testAccountID+"/workers/filters", func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) -// w.Header().Set("content-type", "application/json") -// fmt.Fprintf(w, listRouteResponseData) //nolint -// }) - -// res, err := client.ListWorkerRoutes(context.Background(), "foo") -// want := WorkerRoutesResponse{successResponse, -// []WorkerRoute{ -// {ID: "e7a57d8746e74ae49c25994dadb421b1", Pattern: "app1.example.com/*", Enabled: true}, -// {ID: "f8b68e9857f85bf59c25994dadb421b1", Pattern: "app2.example.com/*", Enabled: false}, -// }, -// } -// if assert.NoError(t, err) { -// assert.Equal(t, want, res) -// } -// } - -// func TestWorkers_ListWorkerRoutesEnt(t *testing.T) { -// setup() -// defer teardown() - -// mux.HandleFunc("/zones"+testAccountID+"/workers/routes", func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) -// w.Header().Set("content-type", "application/json") -// fmt.Fprintf(w, listRouteEntResponseData) //nolint -// }) - -// res, err := client.ListWorkerRoutes(context.Background(), "foo") -// want := WorkerRoutesResponse{successResponse, -// []WorkerRoute{ -// {ID: "e7a57d8746e74ae49c25994dadb421b1", Pattern: "app1.example.com/*", Script: "test_script_1", Enabled: true}, -// {ID: "f8b68e9857f85bf59c25994dadb421b1", Pattern: "app2.example.com/*", Script: "test_script_2", Enabled: true}, -// {ID: "2b5bf4240cd34c77852fac70b1bf745a", Pattern: "app3.example.com/*", Script: "", Enabled: false}, -// }, -// } -// if assert.NoError(t, err) { -// assert.Equal(t, want, res) -// } -// } - -// func TestWorkers_GetWorkerRoute(t *testing.T) { -// setup() -// defer teardown() - -// mux.HandleFunc("/zones"+testAccountID+"/workers/routes/1234", func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) -// w.Header().Set("content-type", "application/json") -// fmt.Fprintf(w, getRouteResponseData) //nolint -// }) - -// res, err := client.GetWorkerRoute(context.Background(), "foo", "1234") -// want := WorkerRouteResponse{successResponse, -// WorkerRoute{ -// ID: "e7a57d8746e74ae49c25994dadb421b1", -// Pattern: "app1.example.com/*", -// Script: "script-name"}, -// } -// if assert.NoError(t, err) { -// assert.Equal(t, want, res) -// } -// } - -// func TestWorkers_UpdateWorkerRoute(t *testing.T) { -// setup() -// defer teardown() - -// mux.HandleFunc("/zones"+testAccountID+"/workers/filters/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) -// w.Header().Set("content-type", "application/json") -// fmt.Fprintf(w, updateWorkerRouteResponse) //nolint -// }) -// route := WorkerRoute{Pattern: "app3.example.com/*", Enabled: true} -// res, err := client.UpdateWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1", route) -// want := WorkerRouteResponse{successResponse, -// WorkerRoute{ -// ID: "e7a57d8746e74ae49c25994dadb421b1", -// Pattern: "app3.example.com/*", -// Enabled: true, -// }} -// if assert.NoError(t, err) { -// assert.Equal(t, want, res) -// } -// } - -// func TestWorkers_UpdateWorkerRouteEnt(t *testing.T) { -// setup() -// defer teardown() - -// mux.HandleFunc("/zones"+testAccountID+"/workers/routes/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) -// w.Header().Set("content-type", "application/json") -// fmt.Fprintf(w, updateWorkerRouteEntResponse) //nolint -// }) -// route := WorkerRoute{Pattern: "app3.example.com/*", Script: "test_script_1"} -// res, err := client.UpdateWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1", route) -// want := WorkerRouteResponse{successResponse, -// WorkerRoute{ -// ID: "e7a57d8746e74ae49c25994dadb421b1", -// Pattern: "app3.example.com/*", -// Script: "test_script_1", -// }} -// if assert.NoError(t, err) { -// assert.Equal(t, want, res) -// } -// } - -// func TestWorkers_UpdateWorkerRouteSingleScriptWithAccount(t *testing.T) { -// setup() -// defer teardown() - -// mux.HandleFunc("/zones"+testAccountID+"/workers/filters/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) -// w.Header().Set("content-type", "application/json") -// fmt.Fprintf(w, updateWorkerRouteEntResponse) //nolint -// }) -// route := WorkerRoute{Pattern: "app3.example.com/*", Enabled: true} -// res, err := client.UpdateWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1", route) -// want := WorkerRouteResponse{successResponse, -// WorkerRoute{ -// ID: "e7a57d8746e74ae49c25994dadb421b1", -// Pattern: "app3.example.com/*", -// Script: "test_script_1", -// }} -// if assert.NoError(t, err) { -// assert.Equal(t, want, res) -// } -// } - -// func TestWorkers_ListWorkerBindingsMultiScript(t *testing.T) { -// setup() -// defer teardown() - -// mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/my-script/bindings", func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) -// w.Header().Set("content-type", "application/json") -// fmt.Fprintf(w, listBindingsResponseData) //nolint -// }) - -// mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/my-script/bindings/MY_WASM/content", func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) -// w.Header().Set("content-type", "application/wasm") -// _, _ = w.Write([]byte("mock multi-script wasm")) -// }) - -// res, err := client.ListWorkerBindings(context.Background(), &WorkerRequestParams{ -// ScriptName: "my-script", -// }) -// assert.NoError(t, err) - -// assert.Equal(t, successResponse, res.Response) -// assert.Equal(t, 7, len(res.BindingList)) - -// assert.Equal(t, res.BindingList[0], WorkerBindingListItem{ -// Name: "MY_KV", -// Binding: WorkerKvNamespaceBinding{ -// NamespaceID: "89f5f8fd93f94cb98473f6f421aa3b65", -// }, -// }) -// assert.Equal(t, WorkerKvNamespaceBindingType, res.BindingList[0].Binding.Type()) - -// assert.Equal(t, "MY_WASM", res.BindingList[1].Name) -// wasmBinding := res.BindingList[1].Binding.(WorkerWebAssemblyBinding) -// wasmModuleContent, err := io.ReadAll(wasmBinding.Module) -// assert.NoError(t, err) -// assert.Equal(t, []byte("mock multi-script wasm"), wasmModuleContent) -// assert.Equal(t, WorkerWebAssemblyBindingType, res.BindingList[1].Binding.Type()) - -// assert.Equal(t, res.BindingList[2], WorkerBindingListItem{ -// Name: "MY_PLAIN_TEXT", -// Binding: WorkerPlainTextBinding{ -// Text: "text", -// }, -// }) -// assert.Equal(t, WorkerPlainTextBindingType, res.BindingList[2].Binding.Type()) - -// assert.Equal(t, res.BindingList[3], WorkerBindingListItem{ -// Name: "MY_SECRET_TEXT", -// Binding: WorkerSecretTextBinding{}, -// }) -// assert.Equal(t, WorkerSecretTextBindingType, res.BindingList[3].Binding.Type()) - -// environment := "MY_ENVIRONMENT" -// assert.Equal(t, res.BindingList[4], WorkerBindingListItem{ -// Name: "MY_SERVICE_BINDING", -// Binding: WorkerServiceBinding{ -// Service: "MY_SERVICE", -// Environment: &environment, -// }, -// }) -// assert.Equal(t, WorkerServiceBindingType, res.BindingList[4].Binding.Type()) - -// assert.Equal(t, res.BindingList[5], WorkerBindingListItem{ -// Name: "MY_NEW_BINDING", -// Binding: WorkerInheritBinding{}, -// }) -// assert.Equal(t, WorkerInheritBindingType, res.BindingList[5].Binding.Type()) - -// assert.Equal(t, res.BindingList[6], WorkerBindingListItem{ -// Name: "MY_BUCKET", -// Binding: WorkerR2BucketBinding{ -// BucketName: "bucket", -// }, -// }) -// assert.Equal(t, WorkerR2BucketBindingType, res.BindingList[6].Binding.Type()) -// } - -// func TestWorkers_UpdateWorkerRouteErrorsWhenMixingSingleAndMultiScriptProperties(t *testing.T) { -// setup() -// defer teardown() - -// route := WorkerRoute{Pattern: "app1.example.com/*", Script: "test_script", Enabled: true} -// _, err := client.UpdateWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1", route) -// assert.EqualError(t, err, "Only `Script` or `Enabled` may be specified for a WorkerRoute, not both") -// } - -// func TestWorkers_UpdateWorkerRouteWithNoScript(t *testing.T) { -// setup() -// defer teardown() - -// mux.HandleFunc("/zones"+testAccountID+"/workers/routes/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) -// w.Header().Set("content-type", "application/json") -// fmt.Fprintf(w, updateWorkerRouteEntResponse) //nolint -// }) - -// route := WorkerRoute{Pattern: "app1.example.com/*"} -// _, err := client.UpdateWorkerRoute(context.Background(), "foo", "e7a57d8746e74ae49c25994dadb421b1", route) -// assert.NoError(t, err) -// } +import ( + "context" + "fmt" + "net/http" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCreateWorkersRoute(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/zones/"+testZoneID+"/workers/routes", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method) + w.Header().Set("content-type", "application/json") + fmt.Fprintf(w, createWorkerRouteResponse) + }) + + res, err := client.CreateWorkerRoute(context.Background(), ZoneIdentifier(testZoneID), CreateWorkerRouteParams{ + Pattern: "app1.example.com/*", + Script: "example", + }) + + want := WorkerRouteResponse{successResponse, WorkerRoute{ID: "e7a57d8746e74ae49c25994dadb421b1"}} + if assert.NoError(t, err) { + assert.Equal(t, want, res) + } +} + +func TestDeleteWorkersRoute(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/zones/"+testZoneID+"/workers/routes/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method) + w.Header().Set("content-type", "application/json") + fmt.Fprintf(w, deleteWorkerRouteResponseData) + }) + res, err := client.DeleteWorkerRoute(context.Background(), ZoneIdentifier(testZoneID), "e7a57d8746e74ae49c25994dadb421b1") + want := WorkerRouteResponse{successResponse, + WorkerRoute{ + ID: "e7a57d8746e74ae49c25994dadb421b1", + }} + if assert.NoError(t, err) { + assert.Equal(t, want, res) + } +} + +func TestListWorkersRoute(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/zones/"+testZoneID+"/workers/routes", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) + w.Header().Set("content-type", "application/json") + fmt.Fprintf(w, listWorkerRouteResponse) + }) + + res, err := client.ListWorkerRoutes(context.Background(), ZoneIdentifier(testZoneID), ListWorkerRoutesParams{}) + want := WorkerRoutesResponse{successResponse, + []WorkerRoute{ + {ID: "e7a57d8746e74ae49c25994dadb421b1", Pattern: "app1.example.com/*", ScriptName: "test_script_1"}, + {ID: "f8b68e9857f85bf59c25994dadb421b1", Pattern: "app2.example.com/*", ScriptName: "test_script_2"}, + {ID: "2b5bf4240cd34c77852fac70b1bf745a", Pattern: "app3.example.com/*", ScriptName: "test_script_3"}, + }, + } + if assert.NoError(t, err) { + assert.Equal(t, want, res) + } +} + +func TestGetWorkersRoute(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/zones/"+testZoneID+"/workers/routes/1234", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) + w.Header().Set("content-type", "application/json") + fmt.Fprintf(w, getRouteResponseData) + }) + + res, err := client.GetWorkerRoute(context.Background(), ZoneIdentifier(testZoneID), "1234") + want := WorkerRouteResponse{successResponse, + WorkerRoute{ + ID: "e7a57d8746e74ae49c25994dadb421b1", + Pattern: "app1.example.com/*", + ScriptName: "script-name"}, + } + if assert.NoError(t, err) { + assert.Equal(t, want, res) + } +} + +func TestUpdateWorkersRoute(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/zones/"+testZoneID+"/workers/routes/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) + w.Header().Set("content-type", "application/json") + fmt.Fprintf(w, updateWorkerRouteEntResponse) + }) + + res, err := client.UpdateWorkerRoute(context.Background(), ZoneIdentifier(testZoneID), UpdateWorkerRouteParams{ + ID: "e7a57d8746e74ae49c25994dadb421b1", + Pattern: "app3.example.com/*", + Script: "test_script_1", + }) + want := WorkerRouteResponse{successResponse, + WorkerRoute{ + ID: "e7a57d8746e74ae49c25994dadb421b1", + Pattern: "app3.example.com/*", + ScriptName: "test_script_1", + }} + if assert.NoError(t, err) { + assert.Equal(t, want, res) + } +} diff --git a/workers_secrets.go b/workers_secrets.go index 09d8ba337..20d30fe54 100644 --- a/workers_secrets.go +++ b/workers_secrets.go @@ -32,11 +32,33 @@ type WorkersListSecretsResponse struct { Result []WorkersSecret `json:"result"` } +type SetWorkersSecretParams struct { + ScriptName string + Secret *WorkersPutSecretRequest +} + +type DeleteWorkersSecretParams struct { + ScriptName string + SecretName string +} + +type ListWorkersSecretsParams struct { + ScriptName string +} + // SetWorkersSecret creates or updates a secret // API reference: https://api.cloudflare.com/ -func (api *API) SetWorkersSecret(ctx context.Context, script string, req *WorkersPutSecretRequest) (WorkersPutSecretResponse, error) { - uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s/secrets", api.AccountID, script) - res, err := api.makeRequestContext(ctx, http.MethodPut, uri, req) +func (api *API) SetWorkersSecret(ctx context.Context, rc *ResourceContainer, params SetWorkersSecretParams) (WorkersPutSecretResponse, error) { + if rc.Level != AccountRouteLevel { + return WorkersPutSecretResponse{}, ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return WorkersPutSecretResponse{}, ErrMissingAccountID + } + + uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s/secrets", rc.Identifier, params.ScriptName) + res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params.Secret) if err != nil { return WorkersPutSecretResponse{}, err } @@ -51,8 +73,16 @@ func (api *API) SetWorkersSecret(ctx context.Context, script string, req *Worker // DeleteWorkersSecret deletes a secret // API reference: https://api.cloudflare.com/ -func (api *API) DeleteWorkersSecret(ctx context.Context, script, secretName string) (Response, error) { - uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s/secrets/%s", api.AccountID, script, secretName) +func (api *API) DeleteWorkersSecret(ctx context.Context, rc *ResourceContainer, params DeleteWorkersSecretParams) (Response, error) { + if rc.Level != AccountRouteLevel { + return Response{}, ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return Response{}, ErrMissingAccountID + } + + uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s/secrets/%s", rc.Identifier, params.ScriptName, params.SecretName) res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil) if err != nil { return Response{}, err @@ -68,8 +98,16 @@ func (api *API) DeleteWorkersSecret(ctx context.Context, script, secretName stri // ListWorkersSecrets lists secrets for a given worker // API reference: https://api.cloudflare.com/ -func (api *API) ListWorkersSecrets(ctx context.Context, script string) (WorkersListSecretsResponse, error) { - uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s/secrets", api.AccountID, script) +func (api *API) ListWorkersSecrets(ctx context.Context, rc *ResourceContainer, params ListWorkersSecretsParams) (WorkersListSecretsResponse, error) { + if rc.Level != AccountRouteLevel { + return WorkersListSecretsResponse{}, ErrRequiredAccountLevelResourceContainer + } + + if rc.Identifier == "" { + return WorkersListSecretsResponse{}, ErrMissingAccountID + } + + uri := fmt.Sprintf("/accounts/%s/workers/scripts/%s/secrets", rc.Identifier, params.ScriptName) res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) if err != nil { return WorkersListSecretsResponse{}, err diff --git a/workers_secrets_test.go b/workers_secrets_test.go index c08ef71dd..55af3d9f1 100644 --- a/workers_secrets_test.go +++ b/workers_secrets_test.go @@ -9,8 +9,8 @@ import ( "github.com/stretchr/testify/assert" ) -func TestWorkers_SetWorkersSecret(t *testing.T) { - setup(UsingAccount("foo")) +func TestSetWorkersSecret(t *testing.T) { + setup() defer teardown() response := `{ @@ -23,7 +23,7 @@ func TestWorkers_SetWorkersSecret(t *testing.T) { "messages": [] }` - mux.HandleFunc("/accounts/foo/workers/scripts/test-script/secrets", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/test-script/secrets", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) w.Header().Set("content-type", "application/javascript") fmt.Fprintf(w, response) //nolint @@ -32,7 +32,7 @@ func TestWorkers_SetWorkersSecret(t *testing.T) { Name: "my-secret", Text: "super-secret", } - res, err := client.SetWorkersSecret(context.Background(), "test-script", req) + res, err := client.SetWorkersSecret(context.Background(), AccountIdentifier(testAccountID), SetWorkersSecretParams{ScriptName: "test-script", Secret: req}) want := WorkersPutSecretResponse{ successResponse, WorkersSecret{ @@ -46,8 +46,8 @@ func TestWorkers_SetWorkersSecret(t *testing.T) { } } -func TestWorkers_DeleteWorkersSecret(t *testing.T) { - setup(UsingAccount("foo")) +func TestDeleteWorkersSecret(t *testing.T) { + setup() defer teardown() response := `{ @@ -60,13 +60,13 @@ func TestWorkers_DeleteWorkersSecret(t *testing.T) { "messages": [] }` - mux.HandleFunc("/accounts/foo/workers/scripts/test-script/secrets/my-secret", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/test-script/secrets/my-secret", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method) w.Header().Set("content-type", "application/javascript") fmt.Fprintf(w, response) //nolint }) - res, err := client.DeleteWorkersSecret(context.Background(), "test-script", "my-secret") + res, err := client.DeleteWorkersSecret(context.Background(), AccountIdentifier(testAccountID), DeleteWorkersSecretParams{ScriptName: "test-script", SecretName: "my-secret"}) want := successResponse if assert.NoError(t, err) { @@ -74,8 +74,8 @@ func TestWorkers_DeleteWorkersSecret(t *testing.T) { } } -func TestWorkers_ListWorkersSecret(t *testing.T) { - setup(UsingAccount("foo")) +func TestListWorkersSecret(t *testing.T) { + setup() defer teardown() response := `{ @@ -88,13 +88,13 @@ func TestWorkers_ListWorkersSecret(t *testing.T) { "messages": [] }` - mux.HandleFunc("/accounts/foo/workers/scripts/test-script/secrets", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/test-script/secrets", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) w.Header().Set("content-type", "application/javascript") fmt.Fprintf(w, response) //nolint }) - res, err := client.ListWorkersSecrets(context.Background(), "test-script") + res, err := client.ListWorkersSecrets(context.Background(), AccountIdentifier(testAccountID), ListWorkersSecretsParams{ScriptName: "test-script"}) want := WorkersListSecretsResponse{ successResponse, []WorkersSecret{ diff --git a/workers_tail.go b/workers_tail.go index 478112b4a..09d7f2fd1 100644 --- a/workers_tail.go +++ b/workers_tail.go @@ -42,6 +42,7 @@ func (api *API) StartWorkersTail(ctx context.Context, rc *ResourceContainer, scr if rc.Identifier == "" { return WorkersTail{}, ErrMissingAccountID } + if scriptName == "" { return WorkersTail{}, ErrMissingScriptName } diff --git a/workers_test.go b/workers_test.go index d3a44d7f4..2e08292c6 100644 --- a/workers_test.go +++ b/workers_test.go @@ -89,7 +89,7 @@ const ( "errors": [], "messages": [] }` - listRouteEntResponseData = `{ + listWorkerRouteResponse = `{ "result": [ { "id": "e7a57d8746e74ae49c25994dadb421b1", @@ -103,7 +103,8 @@ const ( }, { "id": "2b5bf4240cd34c77852fac70b1bf745a", - "pattern": "app3.example.com/*" + "pattern": "app3.example.com/*", + "script": "test_script_3" } ], "success": true, @@ -389,7 +390,7 @@ func TestListWorkers(t *testing.T) { fmt.Fprintf(w, listWorkersResponseData) }) - res, err := client.ListWorkers(context.Background(), AccountIdentifier(testAccountID), ListWorkersParams{}) + res, _, err := client.ListWorkers(context.Background(), AccountIdentifier(testAccountID), ListWorkersParams{}) sampleDate, _ := time.Parse(time.RFC3339Nano, "2018-04-22T17:10:48.938097Z") want := []WorkerMetaData{ { @@ -421,7 +422,7 @@ func TestUploadWorker_Basic(t *testing.T) { w.Header().Set("content-type", "application/json") fmt.Fprintf(w, uploadWorkerResponseData) //nolint }) - res, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{Name: "foo", Script: workerScript}) + res, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ScriptName: "foo", Script: workerScript}) formattedTime, _ := time.Parse(time.RFC3339Nano, "2018-06-09T15:17:01.989141Z") want := WorkerScriptResponse{ successResponse, @@ -460,7 +461,7 @@ func TestUploadWorker_Module(t *testing.T) { w.Header().Set("content-type", "application/json") fmt.Fprintf(w, uploadWorkerModuleResponseData) }) - res, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{Name: "foo", Script: workerModuleScript, Module: true}) + res, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ScriptName: "foo", Script: workerModuleScript, Module: true}) formattedTime, _ := time.Parse(time.RFC3339Nano, "2018-06-09T15:17:01.989141Z") want := WorkerScriptResponse{ successResponse, @@ -506,8 +507,8 @@ func TestUploadWorker_WithDurableObjectBinding(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", handler) _, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ - Name: "bar", - Script: workerScript, + ScriptName: "bar", + Script: workerScript, Bindings: map[string]WorkerBinding{ "b1": WorkerDurableObjectBinding{ ClassName: "TheClass", @@ -563,8 +564,8 @@ func TestUploadWorker_WithInheritBinding(t *testing.T) { }} res, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ - Name: "bar", - Script: workerScript, + ScriptName: "bar", + Script: workerScript, Bindings: map[string]WorkerBinding{ "b1": WorkerInheritBinding{}, "b2": WorkerInheritBinding{ @@ -602,8 +603,8 @@ func TestUploadWorker_WithKVBinding(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", handler) _, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ - Name: "bar", - Script: workerScript, + ScriptName: "bar", + Script: workerScript, Bindings: map[string]WorkerBinding{ "b1": WorkerKvNamespaceBinding{ NamespaceID: "test-namespace", @@ -643,8 +644,8 @@ func TestUploadWorker_WithWasmBinding(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", handler) _, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ - Name: "bar", - Script: workerScript, + ScriptName: "bar", + Script: workerScript, Bindings: map[string]WorkerBinding{ "b1": WorkerWebAssemblyBinding{ Module: strings.NewReader("fake-wasm"), @@ -681,8 +682,8 @@ func TestUploadWorker_WithPlainTextBinding(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", handler) _, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ - Name: "bar", - Script: workerScript, + ScriptName: "bar", + Script: workerScript, Bindings: map[string]WorkerBinding{ "b1": WorkerPlainTextBinding{ Text: "plain text value", @@ -726,9 +727,9 @@ func TestUploadWorker_ModuleWithPlainTextBinding(t *testing.T) { }) _, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ - Name: "bar", - Script: workerModuleScript, - Module: true, + ScriptName: "bar", + Script: workerModuleScript, + Module: true, Bindings: map[string]WorkerBinding{ "b1": WorkerPlainTextBinding{ Text: "plain text value", @@ -765,8 +766,8 @@ func TestUploadWorker_WithSecretTextBinding(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", handler) _, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ - Name: "bar", - Script: workerScript, + ScriptName: "bar", + Script: workerScript, Bindings: map[string]WorkerBinding{ "b1": WorkerSecretTextBinding{ Text: "secret text value", @@ -808,8 +809,8 @@ func TestUploadWorker_WithServiceBinding(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", handler) _, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ - Name: "bar", - Script: workerScript, + ScriptName: "bar", + Script: workerScript, Bindings: map[string]WorkerBinding{ "b1": WorkerServiceBinding{ Service: "the_service", From b40cdd033f824586420f0ba9c0bf8d27b988c865 Mon Sep 17 00:00:00 2001 From: Jacob Bednarz Date: Wed, 30 Nov 2022 15:20:15 +1100 Subject: [PATCH 4/6] update godoc --- workers.go | 2 +- workers_bindings.go | 10 +++++----- workers_routes.go | 8 ++++---- workers_secrets.go | 6 ++++-- workers_tail.go | 6 +++--- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/workers.go b/workers.go index ae2bf7c5d..d5474bc03 100644 --- a/workers.go +++ b/workers.go @@ -103,7 +103,7 @@ type DeleteWorkerParams struct { ScriptName string } -// DeleteWorker deletes worker for a zone. +// DeleteWorker deletes a single Worker. // // API reference: https://api.cloudflare.com/#worker-script-delete-worker func (api *API) DeleteWorker(ctx context.Context, rc *ResourceContainer, params DeleteWorkerParams) error { diff --git a/workers_bindings.go b/workers_bindings.go index d2ac3ee96..963106589 100644 --- a/workers_bindings.go +++ b/workers_bindings.go @@ -106,7 +106,7 @@ func (b WorkerInheritBinding) serialize(bindingName string) (workerBindingMeta, return meta, nil, nil } -// WorkerKvNamespaceBinding is a binding to a Workers KV Namespace +// WorkerKvNamespaceBinding is a binding to a Workers KV Namespace. // // https://developers.cloudflare.com/workers/archive/api/resource-bindings/kv-namespaces/ type WorkerKvNamespaceBinding struct { @@ -130,7 +130,7 @@ func (b WorkerKvNamespaceBinding) serialize(bindingName string) (workerBindingMe }, nil, nil } -// WorkerDurableObjectBinding is a binding to a Workers Durable Object +// WorkerDurableObjectBinding is a binding to a Workers Durable Object. // // https://api.cloudflare.com/#durable-objects-namespace-properties type WorkerDurableObjectBinding struct { @@ -156,7 +156,7 @@ func (b WorkerDurableObjectBinding) serialize(bindingName string) (workerBinding }, nil, nil } -// WorkerWebAssemblyBinding is a binding to a WebAssembly module +// WorkerWebAssemblyBinding is a binding to a WebAssembly module. // // https://developers.cloudflare.com/workers/archive/api/resource-bindings/webassembly-modules/ type WorkerWebAssemblyBinding struct { @@ -190,7 +190,7 @@ func (b WorkerWebAssemblyBinding) serialize(bindingName string) (workerBindingMe }, bodyWriter, nil } -// WorkerPlainTextBinding is a binding to plain text +// WorkerPlainTextBinding is a binding to plain text. // // https://developers.cloudflare.com/workers/tooling/api/scripts/#add-a-plain-text-binding type WorkerPlainTextBinding struct { @@ -214,7 +214,7 @@ func (b WorkerPlainTextBinding) serialize(bindingName string) (workerBindingMeta }, nil, nil } -// WorkerSecretTextBinding is a binding to secret text +// WorkerSecretTextBinding is a binding to secret text. // // https://developers.cloudflare.com/workers/tooling/api/scripts/#add-a-secret-text-binding type WorkerSecretTextBinding struct { diff --git a/workers_routes.go b/workers_routes.go index ec43d9e8b..d6dc1c2a7 100644 --- a/workers_routes.go +++ b/workers_routes.go @@ -25,7 +25,7 @@ type UpdateWorkerRouteParams struct { Script string `json:"script,omitempty"` } -// CreateWorkerRoute creates worker route for a zone +// CreateWorkerRoute creates worker route for a script. // // API reference: https://api.cloudflare.com/#worker-routes-create-route func (api *API) CreateWorkerRoute(ctx context.Context, rc *ResourceContainer, params CreateWorkerRouteParams) (WorkerRouteResponse, error) { @@ -51,7 +51,7 @@ func (api *API) CreateWorkerRoute(ctx context.Context, rc *ResourceContainer, pa return r, nil } -// DeleteWorkerRoute deletes worker route for a zone +// DeleteWorkerRoute deletes worker route for a script. // // API reference: https://api.cloudflare.com/#worker-routes-delete-route func (api *API) DeleteWorkerRoute(ctx context.Context, rc *ResourceContainer, routeID string) (WorkerRouteResponse, error) { @@ -80,7 +80,7 @@ func (api *API) DeleteWorkerRoute(ctx context.Context, rc *ResourceContainer, ro return r, nil } -// ListWorkerRoutes returns list of Worker routes +// ListWorkerRoutes returns list of Worker routes. // // API reference: https://api.cloudflare.com/#worker-routes-list-routes func (api *API) ListWorkerRoutes(ctx context.Context, rc *ResourceContainer, params ListWorkerRoutesParams) (WorkerRoutesResponse, error) { @@ -131,7 +131,7 @@ func (api *API) GetWorkerRoute(ctx context.Context, rc *ResourceContainer, route return r, nil } -// UpdateWorkerRoute updates worker route for a zone. +// UpdateWorkerRoute updates worker route for a script. // // API reference: https://api.cloudflare.com/#worker-routes-update-route func (api *API) UpdateWorkerRoute(ctx context.Context, rc *ResourceContainer, params UpdateWorkerRouteParams) (WorkerRouteResponse, error) { diff --git a/workers_secrets.go b/workers_secrets.go index 20d30fe54..458cd1a7c 100644 --- a/workers_secrets.go +++ b/workers_secrets.go @@ -46,7 +46,8 @@ type ListWorkersSecretsParams struct { ScriptName string } -// SetWorkersSecret creates or updates a secret +// SetWorkersSecret creates or updates a secret. +// // API reference: https://api.cloudflare.com/ func (api *API) SetWorkersSecret(ctx context.Context, rc *ResourceContainer, params SetWorkersSecretParams) (WorkersPutSecretResponse, error) { if rc.Level != AccountRouteLevel { @@ -71,7 +72,8 @@ func (api *API) SetWorkersSecret(ctx context.Context, rc *ResourceContainer, par return result, err } -// DeleteWorkersSecret deletes a secret +// DeleteWorkersSecret deletes a secret. +// // API reference: https://api.cloudflare.com/ func (api *API) DeleteWorkersSecret(ctx context.Context, rc *ResourceContainer, params DeleteWorkersSecretParams) (Response, error) { if rc.Level != AccountRouteLevel { diff --git a/workers_tail.go b/workers_tail.go index 09d7f2fd1..0f074b0b6 100644 --- a/workers_tail.go +++ b/workers_tail.go @@ -35,7 +35,7 @@ type ListWorkersTailResponse struct { Result WorkersTail } -// StartWorkersTail Starts a tail that receives logs and exception from a Worker +// StartWorkersTail Starts a tail that receives logs and exception from a Worker. // // API reference: https://api.cloudflare.com/#worker-tail-logs-start-tail func (api *API) StartWorkersTail(ctx context.Context, rc *ResourceContainer, scriptName string) (WorkersTail, error) { @@ -61,7 +61,7 @@ func (api *API) StartWorkersTail(ctx context.Context, rc *ResourceContainer, scr return workerstailResponse.Result, nil } -// ListWorkersTail Get list of tails currently deployed on a worker +// ListWorkersTail Get list of tails currently deployed on a Worker. // // API reference: https://api.cloudflare.com/#worker-tail-logs-list-tails func (api *API) ListWorkersTail(ctx context.Context, rc *ResourceContainer, params ListWorkersTailParameters) (WorkersTail, error) { @@ -87,7 +87,7 @@ func (api *API) ListWorkersTail(ctx context.Context, rc *ResourceContainer, para return workerstailResponse.Result, nil } -// DeleteWorkersTail Deletes a tail from a Worker +// DeleteWorkersTail Deletes a tail from a Worker. // // API reference: https://api.cloudflare.com/#worker-tail-logs-delete-tail func (api *API) DeleteWorkersTail(ctx context.Context, rc *ResourceContainer, scriptName, tailID string) error { From 50a6512cfcbfcc38e7030aa922d9b6e7eb5db7fc Mon Sep 17 00:00:00 2001 From: Jacob Bednarz Date: Wed, 30 Nov 2022 15:27:03 +1100 Subject: [PATCH 5/6] add changelog entry for workers methods --- .changelog/1137.txt | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .changelog/1137.txt diff --git a/.changelog/1137.txt b/.changelog/1137.txt new file mode 100644 index 000000000..b479d14d4 --- /dev/null +++ b/.changelog/1137.txt @@ -0,0 +1,39 @@ +```release-note:note +workers: all worker methods have been split into product ownership(-ish) files +``` + +```release-note:note +workers: all worker methods now require an explicit `ResourceContainer` for endpoints instead of relying on the globally defined `api.AccountID` +``` + +```release-note:breaking-change +workers: method signatures have been updated to align with the upcoming client conventions +``` + +```release-note:breaking-change +workers: API operations now target account level resources instead of older zone level resources (these are a 1:1 now) +``` + +```release-note:breaking-change +workers_bindings: method signatures have been updated to align with the upcoming client conventions +``` + +```release-note:breaking-change +workers_kv: method signatures have been updated to align with the upcoming client conventions +``` + +```release-note:breaking-change +workers_tails: method signatures have been updated to align with the upcoming client conventions +``` + +```release-note:breaking-change +workers_secrets: method signatures have been updated to align with the upcoming client conventions +``` + +```release-note:breaking-change +workers_routes: method signatures have been updated to align with the upcoming client conventions +``` + +```release-note:breaking-change +workers_cron_triggers: method signatures have been updated to align with the upcoming client conventions +``` From f7fe8394019ddc7245a7f2153736872d039af75a Mon Sep 17 00:00:00 2001 From: Jacob Bednarz Date: Wed, 30 Nov 2022 15:30:46 +1100 Subject: [PATCH 6/6] clean up linter errors --- workers_bindings_test.go | 2 +- workers_kv_test.go | 26 +++++++++++++------------- workers_routes_test.go | 10 +++++----- workers_secrets_test.go | 6 +++--- workers_test.go | 28 ++++++++++++++-------------- 5 files changed, 36 insertions(+), 36 deletions(-) diff --git a/workers_bindings_test.go b/workers_bindings_test.go index a21aec341..f8dea25ad 100644 --- a/workers_bindings_test.go +++ b/workers_bindings_test.go @@ -17,7 +17,7 @@ func TestListWorkerBindings(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/my-script/bindings", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, listBindingsResponseData) + fmt.Fprint(w, listBindingsResponseData) }) mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/my-script/bindings/MY_WASM/content", func(w http.ResponseWriter, r *http.Request) { diff --git a/workers_kv_test.go b/workers_kv_test.go index 1ad7ae091..80d7b140b 100644 --- a/workers_kv_test.go +++ b/workers_kv_test.go @@ -29,7 +29,7 @@ func TestWorkersKV_CreateWorkersKVNamespace(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/storage/kv/namespaces", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method) w.Header().Set("content-type", "application/javascript") - fmt.Fprintf(w, response) //nolint + fmt.Fprint(w, response) }) res, err := client.CreateWorkersKVNamespace(context.Background(), AccountIdentifier(testAccountID), CreateWorkersKVNamespaceParams{Title: "Namespace"}) @@ -60,7 +60,7 @@ func TestWorkersKV_DeleteWorkersKVNamespace(t *testing.T) { mux.HandleFunc(fmt.Sprintf("/accounts/"+testAccountID+"/storage/kv/namespaces/%s", namespace), func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method) w.Header().Set("content-type", "application/javascript") - fmt.Fprintf(w, response) //nolint + fmt.Fprint(w, response) }) res, err := client.DeleteWorkersKVNamespace(context.Background(), AccountIdentifier(testAccountID), namespace) @@ -99,7 +99,7 @@ func TestWorkersKV_ListWorkersKVNamespaces(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/storage/kv/namespaces", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) w.Header().Set("content-type", "application/javascript") - fmt.Fprintf(w, response) //nolint + fmt.Fprint(w, response) }) res, _, err := client.ListWorkersKVNamespaces(context.Background(), AccountIdentifier(testAccountID), ListWorkersKVNamespacesParams{}) @@ -170,10 +170,10 @@ func TestWorkersKV_ListWorkersKVNamespaceMultiplePages(t *testing.T) { w.Header().Set("content-type", "application/javascript") if r.URL.Query().Get("page") == "1" { - fmt.Fprintf(w, response1) //nolint + fmt.Fprint(w, response1) return } else if r.URL.Query().Get("page") == "2" { - fmt.Fprintf(w, response2) //nolint + fmt.Fprint(w, response2) return } else { panic(errors.New("Got a request for an unexpected page")) @@ -218,7 +218,7 @@ func TestWorkersKV_UpdateWorkersKVNamespace(t *testing.T) { mux.HandleFunc(fmt.Sprintf("/accounts/"+testAccountID+"/storage/kv/namespaces/%s", namespace), func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) w.Header().Set("content-type", "application/javascript") - fmt.Fprintf(w, response) //nolint + fmt.Fprint(w, response) }) res, err := client.UpdateWorkersKVNamespace(context.Background(), AccountIdentifier(testAccountID), UpdateWorkersKVNamespaceParams{Title: "Namespace", NamespaceID: namespace}) @@ -246,7 +246,7 @@ func TestWorkersKV_WriteWorkersKVEntry(t *testing.T) { mux.HandleFunc(fmt.Sprintf("/accounts/"+testAccountID+"/storage/kv/namespaces/%s/values/%s", namespace, key), func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) w.Header().Set("content-type", "application/octet-stream") - fmt.Fprintf(w, response) //nolint + fmt.Fprint(w, response) }) want := successResponse @@ -278,7 +278,7 @@ func TestWorkersKV_WriteWorkersKVEntries(t *testing.T) { mux.HandleFunc(fmt.Sprintf("/accounts/"+testAccountID+"/storage/kv/namespaces/%s/bulk", namespace), func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, response) //nolint + fmt.Fprint(w, response) }) want := successResponse @@ -297,7 +297,7 @@ func TestWorkersKV_ReadWorkersKV(t *testing.T) { mux.HandleFunc(fmt.Sprintf("/accounts/"+testAccountID+"/storage/kv/namespaces/%s/values/%s", namespace, key), func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) w.Header().Set("content-type", "text/plain") - fmt.Fprintf(w, "test_value") + fmt.Fprint(w, "test_value") }) res, err := client.GetWorkersKV(context.Background(), AccountIdentifier(testAccountID), GetWorkersKVParams{NamespaceID: namespace, Key: key}) @@ -324,7 +324,7 @@ func TestWorkersKV_DeleteWorkersKVEntry(t *testing.T) { mux.HandleFunc(fmt.Sprintf("/accounts/"+testAccountID+"/storage/kv/namespaces/%s/values/%s", namespace, key), func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method) w.Header().Set("content-type", "application/javascript") - fmt.Fprintf(w, response) //nolint + fmt.Fprint(w, response) }) res, err := client.DeleteWorkersKVEntry(context.Background(), AccountIdentifier(testAccountID), DeleteWorkersKVEntryParams{NamespaceID: namespace, Key: key}) @@ -352,7 +352,7 @@ func TestWorkersKV_DeleteWorkersKVBulk(t *testing.T) { mux.HandleFunc(fmt.Sprintf("/accounts/"+testAccountID+"/storage/kv/namespaces/%s/bulk", namespace), func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, response) //nolint + fmt.Fprint(w, response) }) want := successResponse @@ -386,7 +386,7 @@ func TestWorkersKV_ListKeys(t *testing.T) { mux.HandleFunc(fmt.Sprintf("/accounts/"+testAccountID+"/storage/kv/namespaces/%s/keys", namespace), func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) w.Header().Set("content-type", "application/javascript") - fmt.Fprintf(w, response) //nolint + fmt.Fprint(w, response) }) res, err := client.ListWorkersKVKeys(context.Background(), AccountIdentifier(testAccountID), ListWorkersKVsParams{NamespaceID: namespace}) @@ -456,7 +456,7 @@ func TestWorkersKV_ListKeysWithParameters(t *testing.T) { mux.HandleFunc(fmt.Sprintf("/accounts/"+testAccountID+"/storage/kv/namespaces/%s/keys", namespace), func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) w.Header().Set("content-type", "application/javascript") - fmt.Fprintf(w, response) //nolint + fmt.Fprint(w, response) }) limit, prefix := 25, "test-prefix" diff --git a/workers_routes_test.go b/workers_routes_test.go index f0070a913..8d36fdc9d 100644 --- a/workers_routes_test.go +++ b/workers_routes_test.go @@ -16,7 +16,7 @@ func TestCreateWorkersRoute(t *testing.T) { mux.HandleFunc("/zones/"+testZoneID+"/workers/routes", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, createWorkerRouteResponse) + fmt.Fprint(w, createWorkerRouteResponse) }) res, err := client.CreateWorkerRoute(context.Background(), ZoneIdentifier(testZoneID), CreateWorkerRouteParams{ @@ -37,7 +37,7 @@ func TestDeleteWorkersRoute(t *testing.T) { mux.HandleFunc("/zones/"+testZoneID+"/workers/routes/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, deleteWorkerRouteResponseData) + fmt.Fprint(w, deleteWorkerRouteResponseData) }) res, err := client.DeleteWorkerRoute(context.Background(), ZoneIdentifier(testZoneID), "e7a57d8746e74ae49c25994dadb421b1") want := WorkerRouteResponse{successResponse, @@ -56,7 +56,7 @@ func TestListWorkersRoute(t *testing.T) { mux.HandleFunc("/zones/"+testZoneID+"/workers/routes", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, listWorkerRouteResponse) + fmt.Fprint(w, listWorkerRouteResponse) }) res, err := client.ListWorkerRoutes(context.Background(), ZoneIdentifier(testZoneID), ListWorkerRoutesParams{}) @@ -79,7 +79,7 @@ func TestGetWorkersRoute(t *testing.T) { mux.HandleFunc("/zones/"+testZoneID+"/workers/routes/1234", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, getRouteResponseData) + fmt.Fprint(w, getRouteResponseData) }) res, err := client.GetWorkerRoute(context.Background(), ZoneIdentifier(testZoneID), "1234") @@ -101,7 +101,7 @@ func TestUpdateWorkersRoute(t *testing.T) { mux.HandleFunc("/zones/"+testZoneID+"/workers/routes/e7a57d8746e74ae49c25994dadb421b1", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, updateWorkerRouteEntResponse) + fmt.Fprint(w, updateWorkerRouteEntResponse) }) res, err := client.UpdateWorkerRoute(context.Background(), ZoneIdentifier(testZoneID), UpdateWorkerRouteParams{ diff --git a/workers_secrets_test.go b/workers_secrets_test.go index 55af3d9f1..dc3ac99fa 100644 --- a/workers_secrets_test.go +++ b/workers_secrets_test.go @@ -26,7 +26,7 @@ func TestSetWorkersSecret(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/test-script/secrets", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) w.Header().Set("content-type", "application/javascript") - fmt.Fprintf(w, response) //nolint + fmt.Fprint(w, response) }) req := &WorkersPutSecretRequest{ Name: "my-secret", @@ -63,7 +63,7 @@ func TestDeleteWorkersSecret(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/test-script/secrets/my-secret", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method) w.Header().Set("content-type", "application/javascript") - fmt.Fprintf(w, response) //nolint + fmt.Fprint(w, response) }) res, err := client.DeleteWorkersSecret(context.Background(), AccountIdentifier(testAccountID), DeleteWorkersSecretParams{ScriptName: "test-script", SecretName: "my-secret"}) @@ -91,7 +91,7 @@ func TestListWorkersSecret(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/test-script/secrets", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) w.Header().Set("content-type", "application/javascript") - fmt.Fprintf(w, response) //nolint + fmt.Fprint(w, response) }) res, err := client.ListWorkersSecrets(context.Background(), AccountIdentifier(testAccountID), ListWorkersSecretsParams{ScriptName: "test-script"}) diff --git a/workers_test.go b/workers_test.go index 2e08292c6..647f1af32 100644 --- a/workers_test.go +++ b/workers_test.go @@ -328,7 +328,7 @@ func TestDeleteWorker(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method) w.Header().Set("content-type", "application/javascript") - fmt.Fprintf(w, deleteWorkerResponseData) + fmt.Fprint(w, deleteWorkerResponseData) }) err := client.DeleteWorker(context.Background(), AccountIdentifier(testAccountID), DeleteWorkerParams{ScriptName: "bar"}) @@ -342,7 +342,7 @@ func TestGetWorker(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/foo", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) w.Header().Set("content-type", "application/javascript") - fmt.Fprintf(w, workerScript) + fmt.Fprint(w, workerScript) }) res, err := client.GetWorker(context.Background(), AccountIdentifier(testAccountID), "foo") want := WorkerScriptResponse{ @@ -363,7 +363,7 @@ func TestGetWorker_Module(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/foo", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) w.Header().Set("content-type", "multipart/form-data; boundary=workermodulescriptdownload") - fmt.Fprintf(w, workerModuleScriptDownloadResponse) + fmt.Fprint(w, workerModuleScriptDownloadResponse) }) res, err := client.GetWorker(context.Background(), AccountIdentifier(testAccountID), "foo") @@ -387,7 +387,7 @@ func TestListWorkers(t *testing.T) { mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts", func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, listWorkersResponseData) + fmt.Fprint(w, listWorkersResponseData) }) res, _, err := client.ListWorkers(context.Background(), AccountIdentifier(testAccountID), ListWorkersParams{}) @@ -420,7 +420,7 @@ func TestUploadWorker_Basic(t *testing.T) { contentTypeHeader := r.Header.Get("content-type") assert.Equal(t, "application/javascript", contentTypeHeader, "Expected content-type request header to be 'application/javascript', got %s", contentTypeHeader) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, uploadWorkerResponseData) //nolint + fmt.Fprint(w, uploadWorkerResponseData) }) res, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ScriptName: "foo", Script: workerScript}) formattedTime, _ := time.Parse(time.RFC3339Nano, "2018-06-09T15:17:01.989141Z") @@ -459,7 +459,7 @@ func TestUploadWorker_Module(t *testing.T) { assert.Equal(t, expectedContentType, contentTypeHeader, "Expected content-type request header to be %s, got %s", expectedContentType, contentTypeHeader) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, uploadWorkerModuleResponseData) + fmt.Fprint(w, uploadWorkerModuleResponseData) }) res, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ScriptName: "foo", Script: workerModuleScript, Module: true}) formattedTime, _ := time.Parse(time.RFC3339Nano, "2018-06-09T15:17:01.989141Z") @@ -501,7 +501,7 @@ func TestUploadWorker_WithDurableObjectBinding(t *testing.T) { assert.Equal(t, expectedBindings, mpUpload.BindingMeta) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, uploadWorkerResponseData) + fmt.Fprint(w, uploadWorkerResponseData) } mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", handler) @@ -546,7 +546,7 @@ func TestUploadWorker_WithInheritBinding(t *testing.T) { assert.Equal(t, expectedBindings, mpUpload.BindingMeta) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, uploadWorkerResponseData) + fmt.Fprint(w, uploadWorkerResponseData) } mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", handler) @@ -598,7 +598,7 @@ func TestUploadWorker_WithKVBinding(t *testing.T) { assert.Equal(t, expectedBindings, mpUpload.BindingMeta) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, uploadWorkerResponseData) + fmt.Fprint(w, uploadWorkerResponseData) } mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", handler) @@ -639,7 +639,7 @@ func TestUploadWorker_WithWasmBinding(t *testing.T) { assert.Equal(t, []byte("fake-wasm"), wasmContent) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, uploadWorkerResponseData) + fmt.Fprint(w, uploadWorkerResponseData) } mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", handler) @@ -677,7 +677,7 @@ func TestUploadWorker_WithPlainTextBinding(t *testing.T) { assert.Equal(t, expectedBindings, mpUpload.BindingMeta) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, uploadWorkerResponseData) //nolint + fmt.Fprint(w, uploadWorkerResponseData) } mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", handler) @@ -723,7 +723,7 @@ func TestUploadWorker_ModuleWithPlainTextBinding(t *testing.T) { assert.Equal(t, expectedContentDisposition, contentDispositonHeader, "Expected content-disposition request header to be %s, got %s", expectedContentDisposition, contentDispositonHeader) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, uploadWorkerModuleResponseData) //nolint + fmt.Fprint(w, uploadWorkerModuleResponseData) }) _, err := client.UploadWorker(context.Background(), AccountIdentifier(testAccountID), CreateWorkerParams{ @@ -761,7 +761,7 @@ func TestUploadWorker_WithSecretTextBinding(t *testing.T) { assert.Equal(t, expectedBindings, mpUpload.BindingMeta) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, uploadWorkerResponseData) //nolint + fmt.Fprint(w, uploadWorkerResponseData) } mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", handler) @@ -804,7 +804,7 @@ func TestUploadWorker_WithServiceBinding(t *testing.T) { assert.Equal(t, expectedBindings, mpUpload.BindingMeta) w.Header().Set("content-type", "application/json") - fmt.Fprintf(w, uploadWorkerResponseData) //nolint + fmt.Fprint(w, uploadWorkerResponseData) } mux.HandleFunc("/accounts/"+testAccountID+"/workers/scripts/bar", handler)