diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 0000000..fe8f264 --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,58 @@ +# Configuration for Release Drafter: https://github.com/toolmantim/release-drafter +name-template: 'v$NEXT_PATCH_VERSION 🌈' +tag-template: 'v$NEXT_PATCH_VERSION' +version-template: $MAJOR.$MINOR.$PATCH +# Emoji reference: https://gitmoji.carloscuesta.me/ +categories: + - title: '🚀 Features' + labels: + - 'feature' + - 'enhancement' + - 'kind/feature' + - title: '🐛 Bug Fixes' + labels: + - 'fix' + - 'bugfix' + - 'bug' + - 'regression' + - 'kind/bug' + - title: 📝 Documentation updates + labels: + - documentation + - 'kind/doc' + - title: 👻 Maintenance + labels: + - chore + - dependencies + - 'kind/chore' + - 'kind/dep' + - title: 🚦 Tests + labels: + - test + - tests +exclude-labels: + - reverted + - no-changelog + - skip-changelog + - invalid +autolabeler: + - label: 'documentation' + title: + - '/docs:/i' + - label: 'chore' + title: + - '/chore:/i' + - label: 'bug' + title: + - '/fix:/i' + - label: 'enhancement' + title: + - '/feat:/i' +change-template: '* $TITLE (#$NUMBER) @$AUTHOR' +template: | + ## What’s Changed + + $CHANGES + + ## Thanks to + $CONTRIBUTORS diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..6fa2ba4 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,48 @@ +name: Build + +on: + - pull_request + +jobs: + Test: + runs-on: ubuntu-20.04 + steps: + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: 1.22.x + - uses: actions/checkout@v3.0.0 + - name: Unit Test + run: | + make test + + Build: + runs-on: ubuntu-20.04 + steps: + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: 1.22.x + - uses: actions/checkout@v3.0.0 + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v6 + with: + version: '~> v2' + args: release --clean --snapshot + + BuildImage: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3.0.0 + - name: Image + run: make build-image + + RunE2E: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3.0.0 + - name: Run e2e + run: | + sudo curl -L https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose + sudo chmod u+x /usr/local/bin/docker-compose + make run-e2e diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml new file mode 100644 index 0000000..73fcc4f --- /dev/null +++ b/.github/workflows/release-drafter.yml @@ -0,0 +1,14 @@ +name: Release Drafter + +on: + push: + branches: + - master + +jobs: + UpdateReleaseDraft: + runs-on: ubuntu-20.04 + steps: + - uses: release-drafter/release-drafter@v5 + env: + GITHUB_TOKEN: ${{ secrets.GH_PUBLISH_SECRETS }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..64bd17f --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,100 @@ +name: Release + +on: + push: + tags: + - '*' + branches: + - master + +env: + REGISTRY: ghcr.io + REGISTRY_DOCKERHUB: docker.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + Test: + runs-on: ubuntu-20.04 + steps: + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: 1.22.x + - uses: actions/checkout@v3.0.0 + - name: Unit Test + run: | + make test + + goreleaser: + runs-on: ubuntu-20.04 + if: github.ref != 'refs/heads/master' + steps: + - name: Checkout + uses: actions/checkout@v3.6.0 + with: + fetch-tags: true + fetch-depth: 0 + - name: Set output + id: vars + run: echo "tag=$(git describe --tags)" >> $GITHUB_OUTPUT + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: 1.22.x + - name: Image Registry Login + run: | + docker login --username linuxsuren --password ${{secrets.DOCKER_HUB_PUBLISH_SECRETS}} + docker login ${{ env.REGISTRY }}/linuxsuren --username linuxsuren --password ${{secrets.GH_PUBLISH_SECRETS}} + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v6 + with: + version: '~> v2' + args: release --clean + env: + GITHUB_TOKEN: ${{ secrets.GH_PUBLISH_SECRETS }} + - name: Upload via oras + run: | + export TAG=${{ steps.vars.outputs.tag }} + cd dist + oras push ${{ env.REGISTRY_DOCKERHUB }}/linuxsuren/atest-ext-store-orm:${TAG#v} */* + oras push ${{ env.REGISTRY }}/linuxsuren/atest-ext-store-orm:${TAG#v} */* + + image: + runs-on: ubuntu-20.04 + steps: + - name: Checkout + uses: actions/checkout@v3.0.0 + - name: Setup Docker buildx + uses: docker/setup-buildx-action@79abd3f86f79a9d68a23c75a09a9a85889262adf + - name: Log into registry ${{ env.REGISTRY }} + if: github.event_name != 'pull_request' + uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GH_PUBLISH_SECRETS }} + - name: Log into registry ${{ env.REGISTRY_DOCKERHUB }} + if: github.event_name != 'pull_request' + uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c + with: + registry: ${{ env.REGISTRY_DOCKERHUB }} + username: linuxsuren + password: ${{ secrets.DOCKER_HUB_PUBLISH_SECRETS }} + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + with: + images: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + ${{ env.REGISTRY_DOCKERHUB }}/${{ env.IMAGE_NAME }} + - name: Build and push Docker image + id: build-and-push + uses: docker/build-push-action@ac9327eae2b366085ac7f6a2d02df8aa8ead720a + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64,linux/arm64 + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/Dockerfile b/Dockerfile index ba1c499..73b407e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,12 +10,12 @@ COPY . . RUN GOPROXY=${GOPROXY} go mod download RUN GOPROXY=${GOPROXY} CGO_ENABLED=0 go build -ldflags "-w -s -X github.com/linuxsuren/api-testing/pkg/version.version=${VERSION}\ - -X github.com/linuxsuren/api-testing/pkg/version.date=$(date +%Y-%m-%d)" -o atest-store-iotdb . + -X github.com/linuxsuren/api-testing/pkg/version.date=$(date +%Y-%m-%d)" -o atest-store-iotdb . FROM ${BASE_IMAGE} -LABEL org.opencontainers.image.source=https://github.com/LinuxSuRen/atest-ext-store-orm -LABEL org.opencontainers.image.description="ORM database Store Extension of the API Testing." +LABEL org.opencontainers.image.source=https://github.com/LinuxSuRen/atest-ext-store-iotdb +LABEL org.opencontainers.image.description="IoTDB database Store Extension of the API Testing." COPY --from=builder /workspace/atest-store-iotdb /usr/local/bin/atest-store-iotdb diff --git a/README-zh.md b/README-zh.md new file mode 100644 index 0000000..8832ef5 --- /dev/null +++ b/README-zh.md @@ -0,0 +1,15 @@ +# atest-ext-store-iotdb + +这个项目是 [atest](https://github.com/linuxsuren/api-testing) 框架的一个存储插件。它为操作 IoTDB(时序数据库)提供了支持,用户可以通过 Web UI 的方式轻松操作数据库,包括查询、插入和管理时序数据。 + +## 功能 + +- 与 `api-testing` 框架无缝集成。 +- 提供操作 IoTDB 的 Web UI。 +- 支持查询和管理时序数据。 +- 简化 IoTDB 用户的数据库操作。 + +## 截图 + +![image](https://github.com/user-attachments/assets/e36c4cfd-5a2f-4999-a1fc-2a44bf6c221e) +![image](https://github.com/user-attachments/assets/90a78156-55aa-4877-a442-0832c217dbfb) diff --git a/README.md b/README.md new file mode 100644 index 0000000..c4ae67f --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# atest-ext-store-iotdb + +This project is a storage plugin for the [atest](https://github.com/linuxsuren/api-testing) framework. It provides support for interacting with the IoTDB (Time Series Database) through a web UI. With this plugin, users can easily operate the IoTDB database, including querying, inserting, and managing time-series data. + +## Features + +- Seamless integration with the `api-testing` framework. +- Web UI for interacting with IoTDB. +- Support for querying and managing time-series data. +- Simplifies database operations for IoTDB users. + +## Screenshots + +![image](https://github.com/user-attachments/assets/e36c4cfd-5a2f-4999-a1fc-2a44bf6c221e) +![image](https://github.com/user-attachments/assets/90a78156-55aa-4877-a442-0832c217dbfb) diff --git a/e2e/Dockerfile b/e2e/Dockerfile index bb3a911..76ed4a5 100644 --- a/e2e/Dockerfile +++ b/e2e/Dockerfile @@ -3,6 +3,6 @@ FROM ghcr.io/linuxsuren/api-testing:master WORKDIR /workspace COPY . . -COPY --from=ext /usr/local/bin/atest-store-orm /usr/local/bin/atest-store-orm +COPY --from=ext /usr/local/bin/atest-store-iotdb /usr/local/bin/atest-store-iotdb CMD [ "/workspace/entrypoint.sh" ] diff --git a/e2e/testing-data-query.yaml b/e2e/testing-data-query.yaml index 6348208..366ab0b 100644 --- a/e2e/testing-data-query.yaml +++ b/e2e/testing-data-query.yaml @@ -55,6 +55,6 @@ items: X-Store-Name: "{{.param.store}}" body: | { - "sql": "", + "sql": "show databases", "key": "" - } \ No newline at end of file + } diff --git a/nvim-linux-x86_64.tar.gz b/nvim-linux-x86_64.tar.gz deleted file mode 100644 index 3b38476..0000000 Binary files a/nvim-linux-x86_64.tar.gz and /dev/null differ diff --git a/pkg/convert_test.go b/pkg/convert_test.go index bd4f1c0..d4a324b 100644 --- a/pkg/convert_test.go +++ b/pkg/convert_test.go @@ -208,8 +208,10 @@ func TestConvertToDBHistoryTestResult(t *testing.T) { }) } -var now = time.Now().UTC() -var nowString = now.Format("2006-01-02T15:04:05.999999999") +var ( + now = time.Now().UTC() + nowString = now.Format("2006-01-02T15:04:05.999999999") +) func TestConvertToRemoteHistoryTestResult(t *testing.T) { assert.Equal(t, &server.HistoryTestResult{ diff --git a/pkg/data_query.go b/pkg/data_query.go index 24b79c0..04a45d0 100644 --- a/pkg/data_query.go +++ b/pkg/data_query.go @@ -18,20 +18,21 @@ package pkg import ( "context" "fmt" - "github.com/apache/iotdb-client-go/client" "log" "reflect" "sort" "strings" "time" + "github.com/apache/iotdb-client-go/client" + "github.com/linuxsuren/api-testing/pkg/server" ) func (s *dbserver) Query(ctx context.Context, query *server.DataQuery) (result *server.DataQueryResult, err error) { var db *client.SessionPool var dbQuery DataQuery - if dbQuery, err = s.getClientWithDatabase(ctx, query.Key); err != nil { + if dbQuery, err = s.getClientWithDatabase(ctx); err != nil { return } @@ -81,7 +82,6 @@ func (s *dbserver) Query(ctx context.Context, query *server.DataQuery) (result * func sqlQuery(_ context.Context, sql string, sessionPool *client.SessionPool) (result *server.DataQueryResult, err error) { var session client.Session - var timeout int64 = 1000 if session, err = sessionPool.GetSession(); err != nil { return } @@ -89,7 +89,7 @@ func sqlQuery(_ context.Context, sql string, sessionPool *client.SessionPool) (r var sessionDataSet *client.SessionDataSet fmt.Println("query sql", sql) - if sessionDataSet, err = session.ExecuteQueryStatement(sql, &timeout); err != nil { + if sessionDataSet, err = session.ExecuteStatement(sql); err != nil { return } @@ -100,29 +100,7 @@ func sqlQuery(_ context.Context, sql string, sessionPool *client.SessionPool) (r } columns := sessionDataSet.GetColumnNames() - fmt.Println("columns", columns) - count := 0 - for next, nextErr := sessionDataSet.Next(); next; { - count++ - if count > 10 { - break - } - if nextErr != nil { - err = nextErr - return - } - // Create a slice of interface{}'s to represent each column, - // and a second slice to contain pointers to each item in the columns slice. - columnsData := make([]interface{}, len(columns)) - columnsPointers := make([]interface{}, len(columns)) - for i := range columnsData { - columnsPointers[i] = &columnsData[i] - } - - // Scan the result into the column pointers... - - fmt.Println("get data") - + for next, nextErr := sessionDataSet.Next(); next && nextErr == nil; next, nextErr = sessionDataSet.Next() { // Create our map, and retrieve the value for each column from the pointers slice, // storing it in the map with the name of the column as the key. for _, colName := range columns { @@ -139,12 +117,8 @@ func sqlQuery(_ context.Context, sql string, sessionPool *client.SessionPool) (r break } } - if val == nil { - continue - } rowData.Key = colName - fmt.Println(colName) switch v := val.(type) { case []byte: rowData.Value = string(v) @@ -239,7 +213,7 @@ func (q *commonDataQuery) GetTables(ctx context.Context, currentDatabase string) for _, table := range tableResult.Items { for _, item := range table.GetData() { if item.Key == fmt.Sprintf("Tables_in_%s", currentDatabase) || item.Key == "table_name" || - item.Key == "Tables" || item.Key == "tablename" { + item.Key == "Tables" || item.Key == "tablename" || item.Key == "Timeseries" || item.Key == "ChildPaths" { var found bool for _, name := range tables { if name == item.Value { diff --git a/pkg/inner_sql.go b/pkg/inner_sql.go index 1d7dd7c..d2f5f15 100644 --- a/pkg/inner_sql.go +++ b/pkg/inner_sql.go @@ -41,8 +41,7 @@ func GetInnerSQL(dialect string) InnerSQL { } } -type mysqlDialect struct { -} +type mysqlDialect struct{} func (m *mysqlDialect) ToNativeSQL(query string) (sql string) { if strings.HasPrefix(query, InnerSelectTable_) { @@ -61,8 +60,7 @@ func (m *mysqlDialect) ToNativeSQL(query string) (sql string) { return } -type postgresDialect struct { -} +type postgresDialect struct{} func (p *postgresDialect) ToNativeSQL(query string) (sql string) { if strings.HasPrefix(query, InnerSelectTable_) { @@ -81,8 +79,7 @@ func (p *postgresDialect) ToNativeSQL(query string) (sql string) { return } -type iotdbDialect struct { -} +type iotdbDialect struct{} func (p *iotdbDialect) ToNativeSQL(query string) (sql string) { if strings.HasPrefix(query, InnerSelectTable_) { @@ -92,7 +89,7 @@ func (p *iotdbDialect) ToNativeSQL(query string) (sql string) { } else if query == InnerShowDatabases { sql = "SHOW DATABASES" } else if query == InnerShowTables { - sql = "SELECT * FROM root.*" + sql = "show child paths %s" } else if query == InnerCurrentDB { sql = "SELECT CURRENT_STORAGE_GROUP" } else { diff --git a/pkg/server.go b/pkg/server.go index 676d817..7a8060b 100644 --- a/pkg/server.go +++ b/pkg/server.go @@ -41,7 +41,7 @@ func NewRemoteServer(defaultHistoryLimit int) (s remote.LoaderServer) { return } -func (s *dbserver) getClientWithDatabase(ctx context.Context, dbName string) (dbQuery DataQuery, err error) { +func (s *dbserver) getClientWithDatabase(ctx context.Context) (dbQuery DataQuery, err error) { store := remote.GetStoreFromContext(ctx) if store == nil { err = errors.New("no connect to database") @@ -56,11 +56,13 @@ func (s *dbserver) getClientWithDatabase(ctx context.Context, dbName string) (db } } + timezone := store.Properties["timezone"] config := &client.PoolConfig{ Host: host, Port: port, UserName: store.Username, Password: store.Password, + TimeZone: timezone, } sessionPool := client.NewSessionPool(config, 3, 60000, 60000, false)