feat: port delete from influxdb (#98)

This commit is contained in:
Daniel Moran 2021-05-20 09:20:30 -04:00 committed by GitHub
parent d8ef442b64
commit e4af676ae5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 885 additions and 4 deletions

3
.gitignore vendored
View File

@ -15,5 +15,6 @@ bin/
# Dependency directories
vendor/
# Docs copied from our openapi repo
# Docs generated from our openapi repo
internal/api/cli.yml
internal/api/cli.gen.yml

69
cmd/influx/delete.go Normal file
View File

@ -0,0 +1,69 @@
package main
import (
"github.com/influxdata/influx-cli/v2/internal/cmd/delete"
"github.com/influxdata/influx-cli/v2/pkg/cli/middleware"
"github.com/urfave/cli/v2"
)
func newDeleteCmd() *cli.Command {
var params delete.Params
return &cli.Command{
Name: "delete",
Usage: "Delete points from InfluxDB",
Description: "Delete points from InfluxDB, by specify start, end time and a sql like predicate string",
Flags: append(
commonFlagsNoPrint(),
&cli.GenericFlag{
Name: "org-id",
Usage: "The ID of the organization that owns the bucket",
EnvVars: []string{"INFLUX_ORG_ID"},
Value: &params.OrgID,
},
&cli.StringFlag{
Name: "org",
Usage: "The name of the organization that owns the bucket",
Aliases: []string{"o"},
EnvVars: []string{"INFLUX_ORG"},
Destination: &params.OrgName,
},
&cli.GenericFlag{
Name: "bucket-id",
Usage: "The ID of the bucket to delete from",
EnvVars: []string{"INFLUX_BUCKET_ID"},
Value: &params.BucketID,
},
&cli.StringFlag{
Name: "bucket",
Usage: "The name of the bucket to delete from",
EnvVars: []string{"INFLUX_BUCKET_NAME"},
Destination: &params.BucketName,
},
// NOTE: cli has a Timestamp flag we could use to parse the strings immediately on input,
// but the help-text generation is broken for it.
&cli.StringFlag{
Name: "start",
Usage: "The start time in RFC3339Nano format (ex: '2009-01-02T23:00:00Z')",
Required: true,
Destination: &params.Start,
},
&cli.StringFlag{
Name: "stop",
Usage: "The stop time in RFC3339Nano format (ex: '2009-01-02T23:00:00Z')",
Required: true,
Destination: &params.Stop,
},
&cli.StringFlag{
Name: "predicate",
Usage: "sql like predicate string (ex: 'tag1=\"v1\" and (tag2=123)')",
Aliases: []string{"p"},
Destination: &params.Predicate,
},
),
Before: middleware.WithBeforeFns(withCli(), withApi(true)),
Action: func(ctx *cli.Context) error {
client := delete.Client{CLI: getCLI(ctx), DeleteApi: getAPI(ctx).DeleteApi}
return client.Delete(ctx.Context, &params)
},
}
}

View File

@ -41,6 +41,7 @@ var app = cli.App{
newQueryCmd(),
newConfigCmd(),
newOrgCmd(),
newDeleteCmd(),
},
}

View File

@ -17,7 +17,7 @@ docker run --rm -it -u "$(id -u):$(id -g)" \
-v "${API_DIR}":/api \
${MERGE_DOCKER_IMG} \
swagger-cli bundle /api/contract/cli.yml \
--outfile /api/cli.yml \
--outfile /api/cli.gen.yml \
--type yaml
# Run the generator - This produces many more files than we want to track in git.
@ -26,7 +26,7 @@ docker run --rm -it -u "$(id -u):$(id -g)" \
${GENERATOR_DOCKER_IMG} \
generate \
-g go \
-i /api/cli.yml \
-i /api/cli.gen.yml \
-o /api \
-t /api/templates \
--additional-properties packageName=api,enumClassPrefix=true,generateInterfaces=true

View File

@ -0,0 +1,267 @@
/*
* Subset of Influx API covered by Influx CLI
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 2.0.0
*/
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package api
import (
_gzip "compress/gzip"
_context "context"
_io "io"
_ioutil "io/ioutil"
_nethttp "net/http"
_neturl "net/url"
)
// Linger please
var (
_ _context.Context
)
type DeleteApi interface {
/*
* PostDelete Delete time series data from InfluxDB
* @param ctx _context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
* @return ApiPostDeleteRequest
*/
PostDelete(ctx _context.Context) ApiPostDeleteRequest
/*
* PostDeleteExecute executes the request
*/
PostDeleteExecute(r ApiPostDeleteRequest) error
}
// deleteApiGzipReadCloser supports streaming gzip response-bodies directly from the server.
type deleteApiGzipReadCloser struct {
underlying _io.ReadCloser
gzip _io.ReadCloser
}
func (gzrc *deleteApiGzipReadCloser) Read(p []byte) (int, error) {
return gzrc.gzip.Read(p)
}
func (gzrc *deleteApiGzipReadCloser) Close() error {
if err := gzrc.gzip.Close(); err != nil {
return err
}
return gzrc.underlying.Close()
}
// DeleteApiService DeleteApi service
type DeleteApiService service
type ApiPostDeleteRequest struct {
ctx _context.Context
ApiService DeleteApi
deletePredicateRequest *DeletePredicateRequest
zapTraceSpan *string
org *string
bucket *string
orgID *string
bucketID *string
}
func (r ApiPostDeleteRequest) DeletePredicateRequest(deletePredicateRequest DeletePredicateRequest) ApiPostDeleteRequest {
r.deletePredicateRequest = &deletePredicateRequest
return r
}
func (r ApiPostDeleteRequest) GetDeletePredicateRequest() *DeletePredicateRequest {
return r.deletePredicateRequest
}
func (r ApiPostDeleteRequest) ZapTraceSpan(zapTraceSpan string) ApiPostDeleteRequest {
r.zapTraceSpan = &zapTraceSpan
return r
}
func (r ApiPostDeleteRequest) GetZapTraceSpan() *string {
return r.zapTraceSpan
}
func (r ApiPostDeleteRequest) Org(org string) ApiPostDeleteRequest {
r.org = &org
return r
}
func (r ApiPostDeleteRequest) GetOrg() *string {
return r.org
}
func (r ApiPostDeleteRequest) Bucket(bucket string) ApiPostDeleteRequest {
r.bucket = &bucket
return r
}
func (r ApiPostDeleteRequest) GetBucket() *string {
return r.bucket
}
func (r ApiPostDeleteRequest) OrgID(orgID string) ApiPostDeleteRequest {
r.orgID = &orgID
return r
}
func (r ApiPostDeleteRequest) GetOrgID() *string {
return r.orgID
}
func (r ApiPostDeleteRequest) BucketID(bucketID string) ApiPostDeleteRequest {
r.bucketID = &bucketID
return r
}
func (r ApiPostDeleteRequest) GetBucketID() *string {
return r.bucketID
}
func (r ApiPostDeleteRequest) Execute() error {
return r.ApiService.PostDeleteExecute(r)
}
/*
* PostDelete Delete time series data from InfluxDB
* @param ctx _context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
* @return ApiPostDeleteRequest
*/
func (a *DeleteApiService) PostDelete(ctx _context.Context) ApiPostDeleteRequest {
return ApiPostDeleteRequest{
ApiService: a,
ctx: ctx,
}
}
/*
* Execute executes the request
*/
func (a *DeleteApiService) PostDeleteExecute(r ApiPostDeleteRequest) error {
var (
localVarHTTPMethod = _nethttp.MethodPost
localVarPostBody interface{}
localVarFormFileName string
localVarFileName string
localVarFileBytes []byte
)
localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "DeleteApiService.PostDelete")
if err != nil {
return GenericOpenAPIError{error: err.Error()}
}
localVarPath := localBasePath + "/delete"
localVarHeaderParams := make(map[string]string)
localVarQueryParams := _neturl.Values{}
localVarFormParams := _neturl.Values{}
if r.deletePredicateRequest == nil {
return reportError("deletePredicateRequest is required and must be specified")
}
if r.org != nil {
localVarQueryParams.Add("org", parameterToString(*r.org, ""))
}
if r.bucket != nil {
localVarQueryParams.Add("bucket", parameterToString(*r.bucket, ""))
}
if r.orgID != nil {
localVarQueryParams.Add("orgID", parameterToString(*r.orgID, ""))
}
if r.bucketID != nil {
localVarQueryParams.Add("bucketID", parameterToString(*r.bucketID, ""))
}
// to determine the Content-Type header
localVarHTTPContentTypes := []string{"application/json"}
// set Content-Type header
localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes)
if localVarHTTPContentType != "" {
localVarHeaderParams["Content-Type"] = localVarHTTPContentType
}
// to determine the Accept header
localVarHTTPHeaderAccepts := []string{"application/json"}
// set Accept header
localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts)
if localVarHTTPHeaderAccept != "" {
localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept
}
if r.zapTraceSpan != nil {
localVarHeaderParams["Zap-Trace-Span"] = parameterToString(*r.zapTraceSpan, "")
}
// body params
localVarPostBody = r.deletePredicateRequest
req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFormFileName, localVarFileName, localVarFileBytes)
if err != nil {
return err
}
localVarHTTPResponse, err := a.client.callAPI(req)
if err != nil || localVarHTTPResponse == nil {
return err
}
var body _io.ReadCloser = localVarHTTPResponse.Body
if localVarHTTPResponse.Header.Get("Content-Encoding") == "gzip" {
gzr, err := _gzip.NewReader(body)
if err != nil {
body.Close()
return err
}
body = &deleteApiGzipReadCloser{underlying: body, gzip: gzr}
}
if localVarHTTPResponse.StatusCode >= 300 {
localVarBody, err := _ioutil.ReadAll(body)
body.Close()
if err != nil {
return err
}
newErr := GenericOpenAPIError{
body: localVarBody,
error: localVarHTTPResponse.Status,
}
if localVarHTTPResponse.StatusCode == 400 {
var v Error
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
if err != nil {
newErr.error = err.Error()
return newErr
}
newErr.model = &v
return newErr
}
if localVarHTTPResponse.StatusCode == 403 {
var v Error
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
if err != nil {
newErr.error = err.Error()
return newErr
}
newErr.model = &v
return newErr
}
if localVarHTTPResponse.StatusCode == 404 {
var v Error
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
if err != nil {
newErr.error = err.Error()
return newErr
}
newErr.model = &v
return newErr
}
var v Error
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
if err != nil {
newErr.error = err.Error()
return newErr
}
newErr.model = &v
return newErr
}
return nil
}

View File

@ -51,6 +51,8 @@ type APIClient struct {
BucketsApi BucketsApi
DeleteApi DeleteApi
HealthApi HealthApi
OrganizationsApi OrganizationsApi
@ -82,6 +84,7 @@ func NewAPIClient(cfg *Configuration) *APIClient {
// API Services
c.BucketSchemasApi = (*BucketSchemasApiService)(&c.common)
c.BucketsApi = (*BucketsApiService)(&c.common)
c.DeleteApi = (*DeleteApiService)(&c.common)
c.HealthApi = (*HealthApiService)(&c.common)
c.OrganizationsApi = (*OrganizationsApiService)(&c.common)
c.QueryApi = (*QueryApiService)(&c.common)

View File

@ -33,6 +33,8 @@ paths:
$ref: "./overrides/paths/query.yml"
/users/{userID}:
$ref: "./openapi/src/common/paths/users_userID.yml"
/delete:
$ref: "./openapi/src/common/paths/delete.yml"
components:
parameters:
TraceSpan:
@ -45,6 +47,9 @@ components:
$ref: "./openapi/src/common/parameters/After.yml"
Descending:
$ref: "./openapi/src/common/parameters/Descending.yml"
responses:
ServerError:
$ref: "./openapi/src/common/responses/ServerError.yml"
schemas:
Error:
$ref: "./openapi/src/common/schemas/Error.yml"
@ -134,3 +139,5 @@ components:
$ref: "./openapi/src/common/schemas/Dialect.yml"
Extern:
$ref: "./overrides/schemas/Extern.yml"
DeletePredicateRequest:
$ref: "./openapi/src/common/schemas/DeletePredicateRequest.yml"

@ -1 +1 @@
Subproject commit ea92cf2265f9bfa7d9f70a50c4bade78a263e0e7
Subproject commit 3574e1bce691016496bd0d433a15e97aa255ccb5

View File

@ -0,0 +1,175 @@
/*
* Subset of Influx API covered by Influx CLI
*
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* API version: 2.0.0
*/
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
package api
import (
"encoding/json"
"time"
)
// DeletePredicateRequest The delete predicate request.
type DeletePredicateRequest struct {
// RFC3339Nano
Start time.Time `json:"start"`
// RFC3339Nano
Stop time.Time `json:"stop"`
// InfluxQL-like delete statement
Predicate *string `json:"predicate,omitempty"`
}
// NewDeletePredicateRequest instantiates a new DeletePredicateRequest object
// This constructor will assign default values to properties that have it defined,
// and makes sure properties required by API are set, but the set of arguments
// will change when the set of required properties is changed
func NewDeletePredicateRequest(start time.Time, stop time.Time) *DeletePredicateRequest {
this := DeletePredicateRequest{}
this.Start = start
this.Stop = stop
return &this
}
// NewDeletePredicateRequestWithDefaults instantiates a new DeletePredicateRequest object
// This constructor will only assign default values to properties that have it defined,
// but it doesn't guarantee that properties required by API are set
func NewDeletePredicateRequestWithDefaults() *DeletePredicateRequest {
this := DeletePredicateRequest{}
return &this
}
// GetStart returns the Start field value
func (o *DeletePredicateRequest) GetStart() time.Time {
if o == nil {
var ret time.Time
return ret
}
return o.Start
}
// GetStartOk returns a tuple with the Start field value
// and a boolean to check if the value has been set.
func (o *DeletePredicateRequest) GetStartOk() (*time.Time, bool) {
if o == nil {
return nil, false
}
return &o.Start, true
}
// SetStart sets field value
func (o *DeletePredicateRequest) SetStart(v time.Time) {
o.Start = v
}
// GetStop returns the Stop field value
func (o *DeletePredicateRequest) GetStop() time.Time {
if o == nil {
var ret time.Time
return ret
}
return o.Stop
}
// GetStopOk returns a tuple with the Stop field value
// and a boolean to check if the value has been set.
func (o *DeletePredicateRequest) GetStopOk() (*time.Time, bool) {
if o == nil {
return nil, false
}
return &o.Stop, true
}
// SetStop sets field value
func (o *DeletePredicateRequest) SetStop(v time.Time) {
o.Stop = v
}
// GetPredicate returns the Predicate field value if set, zero value otherwise.
func (o *DeletePredicateRequest) GetPredicate() string {
if o == nil || o.Predicate == nil {
var ret string
return ret
}
return *o.Predicate
}
// GetPredicateOk returns a tuple with the Predicate field value if set, nil otherwise
// and a boolean to check if the value has been set.
func (o *DeletePredicateRequest) GetPredicateOk() (*string, bool) {
if o == nil || o.Predicate == nil {
return nil, false
}
return o.Predicate, true
}
// HasPredicate returns a boolean if a field has been set.
func (o *DeletePredicateRequest) HasPredicate() bool {
if o != nil && o.Predicate != nil {
return true
}
return false
}
// SetPredicate gets a reference to the given string and assigns it to the Predicate field.
func (o *DeletePredicateRequest) SetPredicate(v string) {
o.Predicate = &v
}
func (o DeletePredicateRequest) MarshalJSON() ([]byte, error) {
toSerialize := map[string]interface{}{}
if true {
toSerialize["start"] = o.Start
}
if true {
toSerialize["stop"] = o.Stop
}
if o.Predicate != nil {
toSerialize["predicate"] = o.Predicate
}
return json.Marshal(toSerialize)
}
type NullableDeletePredicateRequest struct {
value *DeletePredicateRequest
isSet bool
}
func (v NullableDeletePredicateRequest) Get() *DeletePredicateRequest {
return v.value
}
func (v *NullableDeletePredicateRequest) Set(val *DeletePredicateRequest) {
v.value = val
v.isSet = true
}
func (v NullableDeletePredicateRequest) IsSet() bool {
return v.isSet
}
func (v *NullableDeletePredicateRequest) Unset() {
v.value = nil
v.isSet = false
}
func NewNullableDeletePredicateRequest(val *DeletePredicateRequest) *NullableDeletePredicateRequest {
return &NullableDeletePredicateRequest{value: val, isSet: true}
}
func (v NullableDeletePredicateRequest) MarshalJSON() ([]byte, error) {
return json.Marshal(v.value)
}
func (v *NullableDeletePredicateRequest) UnmarshalJSON(src []byte) error {
v.isSet = true
return json.Unmarshal(src, &v.value)
}

View File

@ -0,0 +1,69 @@
package delete
import (
"context"
"errors"
"fmt"
"time"
"github.com/influxdata/influx-cli/v2/internal/api"
"github.com/influxdata/influx-cli/v2/internal/cmd"
)
type Client struct {
cmd.CLI
api.DeleteApi
}
type Params struct {
cmd.OrgBucketParams
Predicate string
Start string
Stop string
}
var (
ErrMustSpecifyOrg = errors.New("must specify org ID or org name")
ErrMustSpecifyBucket = errors.New("must specify bucket ID or bucket name")
)
func (c Client) Delete(ctx context.Context, params *Params) error {
if !params.OrgID.Valid() && params.OrgName == "" && c.ActiveConfig.Org == "" {
return ErrMustSpecifyOrg
}
if !params.BucketID.Valid() && params.BucketName == "" {
return ErrMustSpecifyBucket
}
start, err := time.Parse(time.RFC3339Nano, params.Start)
if err != nil {
return fmt.Errorf("start time %q cannot be parsed as RFC3339Nano: %w", params.Start, err)
}
stop, err := time.Parse(time.RFC3339Nano, params.Stop)
if err != nil {
return fmt.Errorf("stop time %q cannot be parsed as RFC3339Nano: %w", params.Stop, err)
}
reqBody := api.NewDeletePredicateRequest(start, stop)
if params.Predicate != "" {
reqBody.SetPredicate(params.Predicate)
}
req := c.PostDelete(ctx).DeletePredicateRequest(*reqBody)
if params.OrgID.Valid() {
req = req.OrgID(params.OrgID.String())
} else if params.OrgName != "" {
req = req.Org(params.OrgName)
} else {
req = req.Org(c.ActiveConfig.Org)
}
if params.BucketID.Valid() {
req = req.BucketID(params.BucketID.String())
} else {
req = req.Bucket(params.BucketName)
}
if err := req.Execute(); err != nil {
return fmt.Errorf("failed to delete data: %w", err)
}
return nil
}

View File

@ -0,0 +1,224 @@
package delete_test
import (
"context"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/influxdata/influx-cli/v2/internal/api"
"github.com/influxdata/influx-cli/v2/internal/cmd"
"github.com/influxdata/influx-cli/v2/internal/cmd/delete"
"github.com/influxdata/influx-cli/v2/internal/config"
"github.com/influxdata/influx-cli/v2/internal/mock"
"github.com/influxdata/influx-cli/v2/pkg/influxid"
"github.com/stretchr/testify/assert"
tmock "github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
func TestClient_Delete(t *testing.T) {
t.Parallel()
id1, _ := influxid.IDFromString("1111111111111111")
id2, _ := influxid.IDFromString("2222222222222222")
start, _ := time.Parse(time.RFC3339Nano, "2020-01-01T00:00:00Z")
stop, _ := time.Parse(time.RFC3339Nano, "2021-01-01T00:00:00Z")
testCases := []struct {
name string
params delete.Params
defaultOrgName string
registerExpectations func(*testing.T, *mock.MockDeleteApi)
expectedErr string
}{
{
name: "by IDs",
params: delete.Params{
OrgBucketParams: cmd.OrgBucketParams{
OrgParams: cmd.OrgParams{
OrgID: id1,
},
BucketParams: cmd.BucketParams{
BucketID: id2,
},
},
Start: start.Format(time.RFC3339Nano),
Stop: stop.Format(time.RFC3339Nano),
},
defaultOrgName: "my-default-org",
registerExpectations: func(t *testing.T, delApi *mock.MockDeleteApi) {
delApi.EXPECT().PostDelete(gomock.Any()).Return(api.ApiPostDeleteRequest{ApiService: delApi})
delApi.EXPECT().PostDeleteExecute(tmock.MatchedBy(func(in api.ApiPostDeleteRequest) bool {
body := in.GetDeletePredicateRequest()
return assert.NotNil(t, body) &&
assert.Equal(t, id1.String(), *in.GetOrgID()) &&
assert.Nil(t, in.GetOrg()) &&
assert.Equal(t, id2.String(), *in.GetBucketID()) &&
assert.Nil(t, in.GetBucket()) &&
assert.Equal(t, start, body.GetStart()) &&
assert.Equal(t, stop, body.GetStop()) &&
assert.Nil(t, body.Predicate)
})).Return(nil)
},
},
{
name: "by org ID, bucket name",
params: delete.Params{
OrgBucketParams: cmd.OrgBucketParams{
OrgParams: cmd.OrgParams{
OrgID: id1,
},
BucketParams: cmd.BucketParams{
BucketName: "my-bucket",
},
},
Start: start.Format(time.RFC3339Nano),
Stop: stop.Format(time.RFC3339Nano),
},
defaultOrgName: "my-default-org",
registerExpectations: func(t *testing.T, delApi *mock.MockDeleteApi) {
delApi.EXPECT().PostDelete(gomock.Any()).Return(api.ApiPostDeleteRequest{ApiService: delApi})
delApi.EXPECT().PostDeleteExecute(tmock.MatchedBy(func(in api.ApiPostDeleteRequest) bool {
body := in.GetDeletePredicateRequest()
return assert.NotNil(t, body) &&
assert.Equal(t, id1.String(), *in.GetOrgID()) &&
assert.Nil(t, in.GetOrg()) &&
assert.Equal(t, "my-bucket", *in.GetBucket()) &&
assert.Nil(t, in.GetBucketID()) &&
assert.Equal(t, start, body.GetStart()) &&
assert.Equal(t, stop, body.GetStop()) &&
assert.Nil(t, body.Predicate)
})).Return(nil)
},
},
{
name: "by org name, bucket ID",
params: delete.Params{
OrgBucketParams: cmd.OrgBucketParams{
OrgParams: cmd.OrgParams{
OrgName: "my-org",
},
BucketParams: cmd.BucketParams{
BucketID: id2,
},
},
Start: start.Format(time.RFC3339Nano),
Stop: stop.Format(time.RFC3339Nano),
Predicate: `foo = "bar"`,
},
defaultOrgName: "my-default-org",
registerExpectations: func(t *testing.T, delApi *mock.MockDeleteApi) {
delApi.EXPECT().PostDelete(gomock.Any()).Return(api.ApiPostDeleteRequest{ApiService: delApi})
delApi.EXPECT().PostDeleteExecute(tmock.MatchedBy(func(in api.ApiPostDeleteRequest) bool {
body := in.GetDeletePredicateRequest()
return assert.NotNil(t, body) &&
assert.Equal(t, "my-org", *in.GetOrg()) &&
assert.Nil(t, in.GetOrgID()) &&
assert.Equal(t, id2.String(), *in.GetBucketID()) &&
assert.Nil(t, in.GetBucket()) &&
assert.Equal(t, start, body.GetStart()) &&
assert.Equal(t, stop, body.GetStop()) &&
assert.Equal(t, `foo = "bar"`, body.GetPredicate())
})).Return(nil)
},
},
{
name: "by names",
params: delete.Params{
OrgBucketParams: cmd.OrgBucketParams{
OrgParams: cmd.OrgParams{},
BucketParams: cmd.BucketParams{
BucketName: "my-bucket",
},
},
Start: start.Format(time.RFC3339Nano),
Stop: stop.Format(time.RFC3339Nano),
Predicate: `foo = "bar"`,
},
defaultOrgName: "my-default-org",
registerExpectations: func(t *testing.T, delApi *mock.MockDeleteApi) {
delApi.EXPECT().PostDelete(gomock.Any()).Return(api.ApiPostDeleteRequest{ApiService: delApi})
delApi.EXPECT().PostDeleteExecute(tmock.MatchedBy(func(in api.ApiPostDeleteRequest) bool {
body := in.GetDeletePredicateRequest()
return assert.NotNil(t, body) &&
assert.Equal(t, "my-default-org", *in.GetOrg()) &&
assert.Nil(t, in.GetOrgID()) &&
assert.Equal(t, "my-bucket", *in.GetBucket()) &&
assert.Nil(t, in.GetBucketID()) &&
assert.Equal(t, start, body.GetStart()) &&
assert.Equal(t, stop, body.GetStop()) &&
assert.Equal(t, `foo = "bar"`, body.GetPredicate())
})).Return(nil)
},
},
{
name: "no org",
expectedErr: delete.ErrMustSpecifyOrg.Error(),
},
{
name: "no bucket",
defaultOrgName: "my-default-org",
expectedErr: delete.ErrMustSpecifyBucket.Error(),
},
{
name: "bad start",
params: delete.Params{
OrgBucketParams: cmd.OrgBucketParams{
BucketParams: cmd.BucketParams{
BucketName: "my-bucket",
},
},
Start: "the beginning",
Stop: stop.Format(time.RFC3339Nano),
Predicate: `foo = "bar"`,
},
defaultOrgName: "my-default-org",
expectedErr: `"the beginning" cannot be parsed`,
},
{
name: "bad stop",
params: delete.Params{
OrgBucketParams: cmd.OrgBucketParams{
OrgParams: cmd.OrgParams{},
BucketParams: cmd.BucketParams{
BucketName: "my-bucket",
},
},
Start: start.Format(time.RFC3339Nano),
Stop: "the end",
Predicate: `foo = "bar"`,
},
defaultOrgName: "my-default-org",
expectedErr: `"the end" cannot be parsed`,
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
api := mock.NewMockDeleteApi(ctrl)
if tc.registerExpectations != nil {
tc.registerExpectations(t, api)
}
client := delete.Client{
CLI: cmd.CLI{ActiveConfig: config.Config{Org: tc.defaultOrgName}},
DeleteApi: api,
}
err := client.Delete(context.Background(), &tc.params)
if tc.expectedErr != "" {
require.Error(t, err)
require.Contains(t, err.Error(), tc.expectedErr)
return
}
require.NoError(t, err)
})
}
}

View File

@ -0,0 +1,64 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/influxdata/influx-cli/v2/internal/api (interfaces: DeleteApi)
// Package mock is a generated GoMock package.
package mock
import (
context "context"
reflect "reflect"
gomock "github.com/golang/mock/gomock"
api "github.com/influxdata/influx-cli/v2/internal/api"
)
// MockDeleteApi is a mock of DeleteApi interface.
type MockDeleteApi struct {
ctrl *gomock.Controller
recorder *MockDeleteApiMockRecorder
}
// MockDeleteApiMockRecorder is the mock recorder for MockDeleteApi.
type MockDeleteApiMockRecorder struct {
mock *MockDeleteApi
}
// NewMockDeleteApi creates a new mock instance.
func NewMockDeleteApi(ctrl *gomock.Controller) *MockDeleteApi {
mock := &MockDeleteApi{ctrl: ctrl}
mock.recorder = &MockDeleteApiMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockDeleteApi) EXPECT() *MockDeleteApiMockRecorder {
return m.recorder
}
// PostDelete mocks base method.
func (m *MockDeleteApi) PostDelete(arg0 context.Context) api.ApiPostDeleteRequest {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PostDelete", arg0)
ret0, _ := ret[0].(api.ApiPostDeleteRequest)
return ret0
}
// PostDelete indicates an expected call of PostDelete.
func (mr *MockDeleteApiMockRecorder) PostDelete(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostDelete", reflect.TypeOf((*MockDeleteApi)(nil).PostDelete), arg0)
}
// PostDeleteExecute mocks base method.
func (m *MockDeleteApi) PostDeleteExecute(arg0 api.ApiPostDeleteRequest) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PostDeleteExecute", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// PostDeleteExecute indicates an expected call of PostDeleteExecute.
func (mr *MockDeleteApiMockRecorder) PostDeleteExecute(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostDeleteExecute", reflect.TypeOf((*MockDeleteApi)(nil).PostDeleteExecute), arg0)
}

View File

@ -9,6 +9,7 @@ package mock
//go:generate go run github.com/golang/mock/mockgen -package mock -destination api_write.gen.go github.com/influxdata/influx-cli/v2/internal/api WriteApi
//go:generate go run github.com/golang/mock/mockgen -package mock -destination api_query.gen.go github.com/influxdata/influx-cli/v2/internal/api QueryApi
//go:generate go run github.com/golang/mock/mockgen -package mock -destination api_users.gen.go github.com/influxdata/influx-cli/v2/internal/api UsersApi
//go:generate go run github.com/golang/mock/mockgen -package mock -destination api_delete.gen.go github.com/influxdata/influx-cli/v2/internal/api DeleteApi
// Other mocks
//go:generate go run github.com/golang/mock/mockgen -package mock -destination config.gen.go -mock_names Service=MockConfigService github.com/influxdata/influx-cli/v2/internal/config Service