Repository: kubeclipper/kubeclipper
Pull request #449 (2022-11-29 07:16:10)

test: add region e2e test
Signed-off-by: lixd <xueduan.li@gmail.com>

<!-- Thanks for sending a pull request! Here are some tips for you:

1. If you want **faster** PR reviews, read how: https://github.com/kubeclipper/community/blob/master/developer-guide/development/the-pr-author-guide-to-getting-through-code-review.md
2. In case you want to know how your PR got reviewed, read: https://github.com/kubeclipper/community/blob/master/developer-guide/development/code-review-guide.md
3. Here are some coding convetions followed by Kubeclipper community: https://github.com/kubeclipper/community/blob/master/developer-guide/development/coding-conventions.md
-->

### What type of PR is this?
<!--
Add one of the following kinds:
/kind bug
/kind cleanup
/kind documentation
/kind feature
/kind design

Optionally add one or more of the following kinds if applicable:
/kind api-change
/kind deprecation
/kind failing-test
/kind flake
/kind regression
-->
/kind flake

### What this PR does / why we need it:

### Which issue(s) this PR fixes:
<!--
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_*
-->
Fixes #

### Special notes for reviewers:
```
list region and fuzzy search
```

### Does this PR introduced a user-facing change?
<!--
If no, just write "None" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".

For more information on release notes see: https://github.com/kubernetes/community/blob/master/contributors/guide/release-notes.md
-->
```release-note
None
```

### Additional documentation, usage docs, etc.:
<!--
This section can be blank if this pull request does not require a release note.
Please use the following format for linking documentation or pass the
section below:
- [KEP]: <link>
- [Usage]: <link>
- [Other doc]: <link>
-->
```docs

```

kubeclipper-bot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubeclipper/kubeclipper/pull/449#" title="Author self-approved">lixd</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **x893675** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @x893675` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubeclipper%2Fkubeclipper).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/kubeclipper/kubeclipper/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["x893675"]} -->
lixd: /assign @x893675
x893675: /lgtm
/approve
kubeclipper-bot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubeclipper/kubeclipper/pull/449#" title="Author self-approved">lixd</a>*, *<a href="https://github.com/kubeclipper/kubeclipper/pull/449#issuecomment-1330389614" title="Approved">x893675</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubeclipper%2Fkubeclipper).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubeclipper/kubeclipper/blob/master/OWNERS)~~ [x893675]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
x893675: /cherrypick release-1.3
kubeclipper-bot: @x893675: once the present PR merges, I will cherry-pick it on top of release-1.3 in a new PR and assign it to you.

<details>

In response to [this](https://github.com/kubeclipper/kubeclipper/pull/449#issuecomment-1330389884):

>/cherrypick release-1.3


Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>

Patch:
diff --git a/pkg/simple/client/kc/api.go b/pkg/simple/client/kc/api.go
index 0e05fb9..4efccaf 100644
--- a/pkg/simple/client/kc/api.go
+++ b/pkg/simple/client/kc/api.go
@@ -53,6 +53,7 @@ const (
 	projectPath          = "/api/tenant.kubeclipper.io/v1/projects"
 	templatePath         = "/api/core.kubeclipper.io/v1/templates"
 	registryPath         = "/api/core.kubeclipper.io/v1/registries"
+	regionPath           = "/api/core.kubeclipper.io/v1/regions"
 )
 
 func (cli *Client) ListNodes(ctx context.Context, query Queries) (*NodesList, error) {
@@ -669,3 +670,14 @@ func (cli *Client) ListRegistries(ctx context.Context, query Queries) (*v1.Regis
 	err = json.NewDecoder(serverResp.body).Decode(&registries)
 	return &registries, err
 }
+
+func (cli *Client) ListRegion(ctx context.Context, query Queries) (*v1.RegionList, error) {
+	serverResp, err := cli.get(ctx, regionPath, query.ToRawQuery(), nil)
+	defer ensureReaderClosed(serverResp)
+	if err != nil {
+		return nil, err
+	}
+	regions := v1.RegionList{}
+	err = json.NewDecoder(serverResp.body).Decode(&regions)
+	return &regions, err
+}
diff --git a/pkg/simple/client/kc/request.go b/pkg/simple/client/kc/request.go
index 9d184f5..4059f48 100644
--- a/pkg/simple/client/kc/request.go
+++ b/pkg/simple/client/kc/request.go
@@ -59,6 +59,14 @@ func (q *Queries) ToRawQuery() url.Values {
 		queryParameters.Set(query.ParameterFieldSelector, q.FieldSelector)
 	}
 
+	if len(q.FuzzySearch) > 0 {
+		var fuzzy string
+		for k, v := range q.FuzzySearch {
+			fuzzy += fmt.Sprintf("%s~%s", k, v)
+		}
+		queryParameters.Set(query.ParameterFuzzySearch, fuzzy)
+	}
+
 	return queryParameters
 }
 


Test patch:
diff --git a/pkg/simple/client/kc/request_test.go b/pkg/simple/client/kc/request_test.go
new file mode 100644
index 0000000..d755928
--- /dev/null
+++ b/pkg/simple/client/kc/request_test.go
@@ -0,0 +1,33 @@
+package kc
+
+import (
+	"net/url"
+	"testing"
+
+	"github.com/kubeclipper/kubeclipper/pkg/query"
+)
+
+func TestQueries_ToRawQuery(t *testing.T) {
+	q := query.New()
+	q.LabelSelector = "a=b"
+	q.FieldSelector = "metadata.name=demo"
+	q.Watch = true
+	q.FuzzySearch = map[string]string{
+		"name": "demo",
+	}
+	kcq := Queries(*q)
+	rawQuery := kcq.ToRawQuery()
+	got := rawQuery.Encode()
+
+	target := make(url.Values)
+	target.Set("paging", "limit=-1,page=0")
+	target.Set("watch", "true")
+	target.Set("fieldSelector", "metadata.name=demo")
+	target.Set("labelSelector", "a=b")
+	target.Set("fuzzy", "name~demo")
+	want := target.Encode()
+
+	if got != want {
+		t.Fatalf("want:%s got:%s\n", want, got)
+	}
+}
diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go
index 0dd660b..d7caee6 100644
--- a/test/e2e/e2e_test.go
+++ b/test/e2e/e2e_test.go
@@ -27,6 +27,7 @@ import (
 
 	_ "github.com/kubeclipper/kubeclipper/test/e2e/cluster"
 	_ "github.com/kubeclipper/kubeclipper/test/e2e/node"
+	_ "github.com/kubeclipper/kubeclipper/test/e2e/region"
 	"github.com/kubeclipper/kubeclipper/test/framework"
 )
 
diff --git a/test/e2e/region/framework.go b/test/e2e/region/framework.go
new file mode 100644
index 0000000..a224c57
--- /dev/null
+++ b/test/e2e/region/framework.go
@@ -0,0 +1,26 @@
+/*
+ *
+ *  * Copyright 2021 KubeClipper Authors.
+ *  *
+ *  * Licensed under the Apache License, Version 2.0 (the "License");
+ *  * you may not use this file except in compliance with the License.
+ *  * You may obtain a copy of the License at
+ *  *
+ *  *     http://www.apache.org/licenses/LICENSE-2.0
+ *  *
+ *  * Unless required by applicable law or agreed to in writing, software
+ *  * distributed under the License is distributed on an "AS IS" BASIS,
+ *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  * See the License for the specific language governing permissions and
+ *  * limitations under the License.
+ *
+ */
+
+package region
+
+import "github.com/onsi/ginkgo"
+
+// SIGDescribe annotates the test with the SIG label.
+func SIGDescribe(text string, body func()) bool {
+	return ginkgo.Describe("[sig-region] "+text, body)
+}
diff --git a/test/e2e/region/region.go b/test/e2e/region/region.go
new file mode 100644
index 0000000..aabc6d0
--- /dev/null
+++ b/test/e2e/region/region.go
@@ -0,0 +1,60 @@
+package region
+
+import (
+	"context"
+	"fmt"
+	"time"
+
+	"github.com/onsi/ginkgo"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	"github.com/kubeclipper/kubeclipper/pkg/query"
+	v1 "github.com/kubeclipper/kubeclipper/pkg/scheme/core/v1"
+	"github.com/kubeclipper/kubeclipper/pkg/simple/client/kc"
+	"github.com/kubeclipper/kubeclipper/test/framework"
+)
+
+var _ = SIGDescribe("[Fast] [Serial] List Region", func() {
+	f := framework.NewDefaultFramework("region")
+	ginkgo.It("list region and check is default region exist", func() {
+		ctx := context.Background()
+		ginkgo.By("list region")
+		q := query.New()
+		q.Limit = -1
+		list, err := f.Client.ListRegion(ctx, kc.Queries(*q))
+		framework.ExpectNoError(err)
+
+		if getDefault(list.Items) == nil {
+			ginkgo.Fail("default region not exist")
+		}
+
+		ginkgo.By("search default region")
+		q = query.New()
+		q.Limit = -1
+		q.FuzzySearch = map[string]string{"name": "default"}
+		list, err = f.Client.ListRegion(ctx, kc.Queries(*q))
+		framework.ExpectNoError(err)
+		region := getDefault(list.Items)
+		if region == nil {
+			ginkgo.Fail("default region not exist")
+		}
+		if !isValidTime(region.CreationTimestamp) {
+			ginkgo.Fail(fmt.Sprintf("default region's create time(%s) is invalid", region.CreationTimestamp.Format(time.RFC3339)))
+		}
+	})
+})
+
+func getDefault(regions []v1.Region) *v1.Region {
+	for _, region := range regions {
+		if region.Name == "default" {
+			return &region
+		}
+	}
+	return nil
+}
+
+// isValidTime if 0 < time.unix < now, we think it's a valid time
+func isValidTime(t metav1.Time) bool {
+	now := metav1.Now()
+	return t.Before(&now) && t.After(time.Unix(0, 0))
+}