package http

import (
	"context"
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/influxdata/influxdb/v2"
	"github.com/influxdata/influxdb/v2/authorizer"
	icontext "github.com/influxdata/influxdb/v2/context"
	httpmock "github.com/influxdata/influxdb/v2/http/mock"
	"github.com/influxdata/influxdb/v2/inmem"
	"github.com/influxdata/influxdb/v2/kit/transport/http"
	"github.com/influxdata/influxdb/v2/kv"
	"github.com/influxdata/influxdb/v2/mock"
	itesting "github.com/influxdata/influxdb/v2/testing"
	"go.uber.org/zap/zaptest"
)

const namespace = "testing"

type fixture struct {
	Org             *influxdb.Organization
	Labels          []*influxdb.Label
	Document        *influxdb.Document
	AnotherDocument *influxdb.Document
}

func setup(t *testing.T) (func(auth influxdb.Authorizer) *httptest.Server, func(serverUrl string) DocumentService, fixture) {
	svc := kv.NewService(zaptest.NewLogger(t), inmem.NewKVStore())
	ctx := context.Background()
	// Need this to make resource creation work.
	// We are not testing authorization in the setup.
	ctx = icontext.SetAuthorizer(ctx, mock.NewMockAuthorizer(true, nil))
	if err := svc.Initialize(ctx); err != nil {
		t.Fatal(err)
	}
	ds, err := svc.CreateDocumentStore(ctx, namespace)
	if err != nil {
		t.Fatalf("failed to create document store: %v", err)
	}

	org := &influxdb.Organization{Name: "org"}
	itesting.MustCreateOrgs(ctx, svc, org)
	l1 := &influxdb.Label{Name: "l1", OrgID: org.ID}
	l2 := &influxdb.Label{Name: "l2", OrgID: org.ID}
	l3 := &influxdb.Label{Name: "l3", OrgID: org.ID}
	itesting.MustCreateLabels(ctx, svc, l1, l2, l3)
	doc := &influxdb.Document{
		Content:       "I am a free document",
		Labels:        []*influxdb.Label{l1, l3},
		Organizations: map[influxdb.ID]influxdb.UserType{org.ID: influxdb.Owner},
	}
	if err := ds.CreateDocument(ctx, doc); err != nil {
		panic(err)
	}
	// Organizations are needed only for creation.
	// Need to cleanup for comparison later.
	doc.Organizations = nil
	adoc := &influxdb.Document{
		Content:       "I am another document",
		Labels:        []*influxdb.Label{l1, l2},
		Organizations: map[influxdb.ID]influxdb.UserType{org.ID: influxdb.Owner},
	}
	if err := ds.CreateDocument(ctx, adoc); err != nil {
		panic(err)
	}
	// Organizations are needed only for creation.
	// Need to cleanup for comparison later.
	adoc.Organizations = nil
	backend := NewMockDocumentBackend(t)
	backend.HTTPErrorHandler = http.ErrorHandler(0)
	backend.DocumentService = authorizer.NewDocumentService(svc)
	backend.LabelService = authorizer.NewLabelServiceWithOrg(svc, svc)
	serverFn := func(auth influxdb.Authorizer) *httptest.Server {
		handler := httpmock.NewAuthMiddlewareHandler(NewDocumentHandler(backend), auth)
		return httptest.NewServer(handler)
	}
	clientFn := func(serverUrl string) DocumentService {
		return NewDocumentService(mustNewHTTPClient(t, serverUrl, ""))
	}
	f := fixture{
		Org:             org,
		Labels:          []*influxdb.Label{l1, l2, l3},
		Document:        doc,
		AnotherDocument: adoc,
	}
	return serverFn, clientFn, f
}

func (f fixture) auth(action influxdb.Action) *influxdb.Authorization {
	a := &influxdb.Authorization{
		Permissions: []influxdb.Permission{
			{
				Action: action,
				Resource: influxdb.Resource{
					Type:  influxdb.DocumentsResourceType,
					OrgID: &f.Org.ID,
				},
			},
		},
		Status: influxdb.Active,
	}
	if action == influxdb.WriteAction {
		a.Permissions = append(a.Permissions, influxdb.Permission{
			Action: influxdb.ReadAction,
			Resource: influxdb.Resource{
				Type:  influxdb.DocumentsResourceType,
				OrgID: &f.Org.ID,
			},
		})
	}
	return a
}

func (f fixture) authKO() *influxdb.Authorization {
	return &influxdb.Authorization{
		Status: influxdb.Active,
	}
}

func (f fixture) addLabelPermission(auth *influxdb.Authorization, action influxdb.Action, lid influxdb.ID) {
	ps := []influxdb.Permission{
		{
			Action: action,
			Resource: influxdb.Resource{
				Type: influxdb.LabelsResourceType,
				ID:   &lid,
			},
		},
	}
	if action == influxdb.WriteAction {
		ps = append(ps, influxdb.Permission{
			Action: influxdb.ReadAction,
			Resource: influxdb.Resource{
				Type: influxdb.LabelsResourceType,
				ID:   &lid,
			},
		})
	}
	auth.Permissions = append(auth.Permissions, ps...)
}

// TestDocumentService tests all the service functions using the document HTTP client.
func TestDocumentService(t *testing.T) {
	tests := []struct {
		name string
		fn   func(t *testing.T)
	}{
		{
			name: "CreateDocument",
			fn:   CreateDocument,
		},
		{
			name: "GetDocument",
			fn:   GetDocument,
		},
		{
			name: "GetDocuments",
			fn:   GetDocuments,
		},
		{
			name: "UpdateDocument",
			fn:   UpdateDocument,
		},
		{
			name: "DeleteDocument",
			fn:   DeleteDocument,
		},

		{
			name: "GetLabels",
			fn:   GetLabels,
		},
		{
			name: "AddLabels",
			fn:   AddLabels,
		},
		{
			name: "DeleteLabel",
			fn:   DeleteLabel,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tt.fn(t)
		})
	}
}

func CreateDocument(t *testing.T) {
	t.Run("with content", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(fx.auth(influxdb.WriteAction))
		defer server.Close()
		client := clientFn(server.URL)
		orgID := fx.Org.ID
		d := &influxdb.Document{
			Content: "I am the content",
		}
		if err := client.CreateDocument(context.Background(), namespace, orgID, d); err != nil {
			t.Fatal(err)
		}
		if d.ID <= 1 {
			t.Errorf("invalid document id: %v", d.ID)
		}
		if diff := cmp.Diff(d.Content, "I am the content"); diff != "" {
			t.Errorf("got unexpected content:\n\t%s", diff)
		}
		if len(d.Labels) > 0 {
			t.Errorf("got unexpected labels: %v", d.Labels)
		}
	})

	t.Run("with content and labels", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(fx.auth(influxdb.WriteAction))
		defer server.Close()
		client := clientFn(server.URL)
		orgID := fx.Org.ID
		d := &influxdb.Document{
			Content: "I am the content",
			Labels:  fx.Labels,
		}
		if err := client.CreateDocument(context.Background(), namespace, orgID, d); err != nil {
			t.Fatal(err)
		}
		if d.ID <= 1 {
			t.Errorf("invalid document id: %v", d.ID)
		}
		if diff := cmp.Diff(d.Content, "I am the content"); diff != "" {
			t.Errorf("got unexpected content:\n\t%s", diff)
		}
		if diff := cmp.Diff(d.Labels, fx.Labels); diff != "" {
			t.Errorf("got unexpected labels:\n\t%v", diff)
		}
	})

	t.Run("bad label", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(fx.auth(influxdb.WriteAction))
		defer server.Close()
		client := clientFn(server.URL)
		orgID := fx.Org.ID
		d := &influxdb.Document{
			Content: "I am the content",
			Labels: []*influxdb.Label{
				{
					ID:   influxdb.ID(1),
					Name: "bad",
				},
			},
		}
		if err := client.CreateDocument(context.Background(), namespace, orgID, d); err != nil {
			if !strings.Contains(err.Error(), "label not found") {
				t.Errorf("unexpected error: %v", err)
			}
		} else {
			t.Error("expected error got none")
		}
	})

	t.Run("unauthorized", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(fx.authKO())
		defer server.Close()
		client := clientFn(server.URL)
		d := &influxdb.Document{
			Content: "I am the content",
		}
		if err := client.CreateDocument(context.Background(), namespace, fx.Org.ID, d); err != nil {
			if influxdb.ErrorCode(err) != influxdb.EUnauthorized {
				t.Errorf("unexpected error: %v", err)
			}
		} else {
			t.Error("expected error got none")
		}
	})

	t.Run("unauthorized - insufficient", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(fx.auth(influxdb.ReadAction))
		defer server.Close()
		client := clientFn(server.URL)
		d := &influxdb.Document{
			Content: "I am the content",
		}
		if err := client.CreateDocument(context.Background(), namespace, fx.Org.ID, d); err != nil {
			if influxdb.ErrorCode(err) != influxdb.EUnauthorized {
				t.Errorf("unexpected error: %v", err)
			}
		} else {
			t.Error("expected error got none")
		}
	})
}

func GetDocument(t *testing.T) {
	t.Run("existing", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		want := fx.Document
		server := serverFn(fx.auth(influxdb.ReadAction))
		defer server.Close()
		client := clientFn(server.URL)
		got, err := client.GetDocument(context.Background(), namespace, want.ID)
		if err != nil {
			t.Fatal(err)
		}
		if diff := cmp.Diff(got, want); diff != "" {
			t.Errorf("got unexpected document:\n\t%s", diff)
		}
	})

	t.Run("non existing", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		id := fx.Document.ID + 42
		server := serverFn(fx.auth(influxdb.ReadAction))
		defer server.Close()
		client := clientFn(server.URL)
		if _, err := client.GetDocument(context.Background(), namespace, id); err != nil {
			if !strings.Contains(err.Error(), "document not found") {
				t.Errorf("unexpected error: %v", err)
			}
		} else {
			t.Error("expected error got none")
		}
	})

	t.Run("unauthorized", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(fx.authKO())
		defer server.Close()
		client := clientFn(server.URL)
		if _, err := client.GetDocument(context.Background(), namespace, fx.Document.ID); err != nil {
			if influxdb.ErrorCode(err) != influxdb.EUnauthorized {
				t.Errorf("unexpected error: %v", err)
			}
		} else {
			t.Error("expected error got none")
		}
	})
}

func GetDocuments(t *testing.T) {
	t.Run("get existing documents", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(fx.auth(influxdb.ReadAction))
		defer server.Close()
		client := clientFn(server.URL)
		got, err := client.GetDocuments(context.Background(), namespace, fx.Org.ID)
		if err != nil {
			t.Fatal(err)
		}
		want := []*influxdb.Document{fx.Document, fx.AnotherDocument}
		want[0].Content = nil // response will not contain the content of documents
		want[1].Content = nil // response will not contain the content of documents
		if diff := cmp.Diff(got, want); diff != "" {
			t.Errorf("got unexpected document:\n\t%s", diff)
		}
	})

	t.Run("unauthorized", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(fx.authKO())
		defer server.Close()
		client := clientFn(server.URL)
		docs, err := client.GetDocuments(context.Background(), namespace, fx.Org.ID)
		if err != nil {
			t.Fatal(err)
		}
		if len(docs) > 0 {
			t.Fatalf("no document expected, returned %v instead", docs)
		}
	})
}

func UpdateDocument(t *testing.T) {
	t.Run("update content", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(fx.auth(influxdb.WriteAction))
		defer server.Close()
		client := clientFn(server.URL)
		want := fx.Document
		want.Content = "new content"
		if err := client.UpdateDocument(context.Background(), namespace, want); err != nil {
			t.Fatal(err)
		}
		got, err := client.GetDocument(context.Background(), namespace, want.ID)
		if err != nil {
			t.Fatal(err)
		}
		if diff := cmp.Diff(got, want); diff != "" {
			t.Errorf("got unexpected document:\n\t%s", diff)
		}
	})

	t.Run("update labels", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(fx.auth(influxdb.WriteAction))
		defer server.Close()
		client := clientFn(server.URL)
		want := fx.Document
		want.Labels = want.Labels[:0]
		if err := client.UpdateDocument(context.Background(), namespace, want); err != nil {
			t.Fatal(err)
		}
		got, err := client.GetDocument(context.Background(), namespace, want.ID)
		if err != nil {
			t.Fatal(err)
		}
		if diff := cmp.Diff(got, want); diff != "" {
			t.Errorf("got unexpected document:\n\t%s", diff)
		}
	})

	t.Run("update meta", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(fx.auth(influxdb.WriteAction))
		defer server.Close()
		client := clientFn(server.URL)
		want := fx.Document
		want.Meta.Name = "new name"
		if err := client.UpdateDocument(context.Background(), namespace, want); err != nil {
			t.Fatal(err)
		}
		got, err := client.GetDocument(context.Background(), namespace, want.ID)
		if err != nil {
			t.Fatal(err)
		}
		if diff := cmp.Diff(got, want); diff != "" {
			t.Errorf("got unexpected document:\n\t%s", diff)
		}
	})

	t.Run("unauthorized - wrong org", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(func() influxdb.Authorizer {
			a := fx.auth(influxdb.WriteAction)
			for _, p := range a.Permissions {
				*p.Resource.OrgID++
			}
			return a
		}())
		defer server.Close()
		client := clientFn(server.URL)
		want := fx.AnotherDocument
		want.Content = "new content"
		if err := client.UpdateDocument(context.Background(), namespace, want); err != nil {
			if influxdb.ErrorCode(err) != influxdb.EUnauthorized {
				t.Errorf("unexpected error: %v", err)
			}
		} else {
			t.Error("expected error got none")
		}
	})

	t.Run("unauthorized - insufficient permissions", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(fx.authKO())
		defer server.Close()
		client := clientFn(server.URL)
		want := fx.Document
		want.Content = "new content"
		if err := client.UpdateDocument(context.Background(), namespace, want); err != nil {
			if influxdb.ErrorCode(err) != influxdb.EUnauthorized {
				t.Errorf("unexpected error: %v", err)
			}
		} else {
			t.Error("expected error got none")
		}
	})
}

func DeleteDocument(t *testing.T) {
	t.Run("existing", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		want := fx.Document
		server := serverFn(fx.auth(influxdb.WriteAction))
		defer server.Close()
		client := clientFn(server.URL)
		pre, err := client.GetDocuments(context.Background(), namespace, fx.Org.ID)
		if err != nil {
			t.Fatal(err)
		}
		l := len(pre)
		if err := client.DeleteDocument(context.Background(), namespace, want.ID); err != nil {
			t.Fatal(err)
		}
		got, err := client.GetDocuments(context.Background(), namespace, fx.Org.ID)
		if err != nil {
			t.Fatal(err)
		}
		lgot := len(got)
		lwant := l - 1
		if diff := cmp.Diff(lgot, lwant); diff != "" {
			t.Errorf("got unexpected length of docs:\n\t%v", diff)
		}
	})

	t.Run("non existing", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		id := fx.Document.ID + 42
		server := serverFn(fx.auth(influxdb.WriteAction))
		defer server.Close()
		client := clientFn(server.URL)
		if err := client.DeleteDocument(context.Background(), namespace, id); err != nil {
			if !strings.Contains(err.Error(), "document not found") {
				t.Errorf("unexpected error: %v", err)
			}
		} else {
			t.Error("expected error got none")
		}
		got, err := client.GetDocuments(context.Background(), namespace, fx.Org.ID)
		if err != nil {
			t.Fatal(err)
		}
		lgot := len(got)
		lwant := 2
		if diff := cmp.Diff(lgot, lwant); diff != "" {
			t.Errorf("got unexpected length of docs:\n\t%v", diff)
		}
	})

	t.Run("unauthorized", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(fx.authKO())
		defer server.Close()
		client := clientFn(server.URL)
		if err := client.DeleteDocument(context.Background(), namespace, fx.Document.ID); err != nil {
			if influxdb.ErrorCode(err) != influxdb.EUnauthorized {
				t.Errorf("unexpected error: %v", err)
			}
		} else {
			t.Error("expected error got none")
		}
	})

	t.Run("unauthorized - insufficient", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(fx.auth(influxdb.ReadAction))
		defer server.Close()
		client := clientFn(server.URL)
		if err := client.DeleteDocument(context.Background(), namespace, fx.Document.ID); err != nil {
			if influxdb.ErrorCode(err) != influxdb.EUnauthorized {
				t.Errorf("unexpected error: %v", err)
			}
		} else {
			t.Error("expected error got none")
		}
	})
}

func GetLabels(t *testing.T) {
	t.Run("get labels", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		// GetLabels does not pass through the LabelService. Org permissions are enough.
		server := serverFn(fx.auth(influxdb.ReadAction))
		defer server.Close()
		client := clientFn(server.URL)
		got, err := client.GetDocumentLabels(context.Background(), namespace, fx.Document.ID)
		if err != nil {
			t.Fatal(err)
		}
		want := fx.Document.Labels
		if diff := cmp.Diff(got, want); diff != "" {
			t.Errorf("got unexpected labels:\n\t%s", diff)
		}
	})

	t.Run("unauthorized", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(fx.authKO())
		defer server.Close()
		client := clientFn(server.URL)
		if _, err := client.GetDocumentLabels(context.Background(), namespace, fx.AnotherDocument.ID); err != nil {
			if influxdb.ErrorCode(err) != influxdb.EUnauthorized {
				t.Errorf("unexpected error: %v", err)
			}
		} else {
			t.Error("expected error got none")
		}
	})
}

func AddLabels(t *testing.T) {
	t.Run("add one", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(func() influxdb.Authorizer {
			a := fx.auth(influxdb.WriteAction)
			// The LabelService uses a "standard auth" mode.
			// That's  why we need to add further permissions and the org ones are not enough.
			fx.addLabelPermission(a, influxdb.WriteAction, fx.Labels[1].ID)
			return a
		}())
		defer server.Close()
		client := clientFn(server.URL)
		got, err := client.AddDocumentLabel(context.Background(), namespace, fx.Document.ID, fx.Labels[1].ID)
		if err != nil {
			t.Fatal(err)
		}
		want := fx.Labels[1]
		if diff := cmp.Diff(got, want); diff != "" {
			t.Errorf("got unexpected labels:\n\t%s", diff)
		}
		gotLs, err := client.GetDocumentLabels(context.Background(), namespace, fx.Document.ID)
		if err != nil {
			t.Fatal(err)
		}
		wantLs := fx.Labels
		if diff := cmp.Diff(gotLs, wantLs); diff != "" {
			t.Errorf("got unexpected labels:\n\t%s", diff)
		}
	})

	t.Run("unauthorized", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(fx.authKO())
		defer server.Close()
		client := clientFn(server.URL)
		if _, err := client.AddDocumentLabel(context.Background(), namespace, fx.Document.ID, fx.Labels[1].ID); err != nil {
			if influxdb.ErrorCode(err) != influxdb.EUnauthorized {
				t.Errorf("unexpected error: %v", err)
			}
		} else {
			t.Error("expected error got none")
		}
	})

	t.Run("unauthorized - insufficient", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(func() influxdb.Authorizer {
			a := fx.auth(influxdb.WriteAction)
			fx.addLabelPermission(a, influxdb.ReadAction, fx.Labels[1].ID)
			return a
		}())
		defer server.Close()
		client := clientFn(server.URL)
		if _, err := client.AddDocumentLabel(context.Background(), namespace, fx.Document.ID, fx.Labels[1].ID); err != nil {
			if influxdb.ErrorCode(err) != influxdb.EUnauthorized {
				t.Errorf("unexpected error: %v", err)
			}
		} else {
			t.Error("expected error got none")
		}
	})

	t.Run("add same twice", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(func() influxdb.Authorizer {
			a := fx.auth(influxdb.WriteAction)
			// The LabelService uses a "standard auth" mode.
			// That's  why we need to add further permissions and the org ones are not enough.
			fx.addLabelPermission(a, influxdb.WriteAction, fx.Labels[0].ID)
			return a
		}())
		defer server.Close()
		client := clientFn(server.URL)
		if _, err := client.AddDocumentLabel(context.Background(), namespace, fx.Document.ID, fx.Labels[0].ID); err != nil {
			if !strings.Contains(err.Error(), influxdb.ErrLabelExistsOnResource.Msg) {
				t.Errorf("unexpected error: %v", err.Error())
			}
		} else {
			t.Error("expected error got none")
		}
	})
}

func DeleteLabel(t *testing.T) {
	t.Run("existing", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(func() influxdb.Authorizer {
			a := fx.auth(influxdb.WriteAction)
			// The LabelService uses a "standard auth" mode.
			// That's  why we need to add further permissions and the org ones are not enough.
			fx.addLabelPermission(a, influxdb.WriteAction, fx.Document.Labels[0].ID)
			return a
		}())
		defer server.Close()
		client := clientFn(server.URL)
		pre, err := client.GetDocumentLabels(context.Background(), namespace, fx.Document.ID)
		if err != nil {
			t.Fatal(err)
		}
		l := len(pre)
		if err := client.DeleteDocumentLabel(context.Background(), namespace, fx.Document.ID, fx.Document.Labels[0].ID); err != nil {
			t.Fatal(err)
		}
		got, err := client.GetDocumentLabels(context.Background(), namespace, fx.Document.ID)
		if err != nil {
			t.Fatal(err)
		}
		lgot := len(got)
		lwant := l - 1
		if diff := cmp.Diff(lgot, lwant); diff != "" {
			t.Errorf("got unexpected length of docs:\n\t%v", diff)
		}
	})

	t.Run("non existing", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		badLId := fx.Labels[2].ID + 42
		server := serverFn(func() influxdb.Authorizer {
			a := fx.auth(influxdb.WriteAction)
			fx.addLabelPermission(a, influxdb.WriteAction, badLId)
			return a
		}())
		defer server.Close()
		client := clientFn(server.URL)
		if err := client.DeleteDocumentLabel(context.Background(), namespace, fx.Document.ID, badLId); err != nil {
			if !strings.Contains(err.Error(), "label not found") {
				t.Errorf("unexpected error: %v", err)
			}
		} else {
			t.Error("expected error got none")
		}
		got, err := client.GetDocumentLabels(context.Background(), namespace, fx.Document.ID)
		if err != nil {
			t.Fatal(err)
		}
		lgot := len(got)
		lwant := 2
		if diff := cmp.Diff(lgot, lwant); diff != "" {
			t.Errorf("got unexpected length of labels:\n\t%v", diff)
		}
	})

	t.Run("unauthorized - insufficient", func(t *testing.T) {
		serverFn, clientFn, fx := setup(t)
		server := serverFn(func() influxdb.Authorizer {
			a := fx.auth(influxdb.WriteAction)
			fx.addLabelPermission(a, influxdb.ReadAction, fx.Document.Labels[0].ID)
			return a
		}())
		defer server.Close()
		client := clientFn(server.URL)
		if err := client.DeleteDocumentLabel(context.Background(), namespace, fx.Document.ID, fx.Document.Labels[0].ID); err != nil {
			if influxdb.ErrorCode(err) != influxdb.EUnauthorized {
				t.Errorf("unexpected error: %v", err)
			}
		} else {
			t.Error("expected error got none")
		}
		got, err := client.GetDocumentLabels(context.Background(), namespace, fx.Document.ID)
		if err != nil {
			t.Fatal(err)
		}
		lgot := len(got)
		lwant := 2
		if diff := cmp.Diff(lgot, lwant); diff != "" {
			t.Errorf("got unexpected length of labels:\n\t%v", diff)
		}
	})
}
