Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate assertions from cli #22

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 148 additions & 0 deletions cli/cmd/generate_assertions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package cmd

import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"net/url"
"strings"
"time"

clickhouse "github.com/ClickHouse/clickhouse-go/v2"
"github.com/spf13/cobra"
)

var generateAssertionCmd = &cobra.Command{
Use: "assertion",
Short: "generates assertion",
Long: "generates assertions based on traces generated on previous run",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
log.Println("ASSERTION GENERATION STARTED...")
var result []Repo
reponame := args[0]
if Config.ClickHouseUrl == "" {
log.Println(`Please set the Clickhouse url using this command:
qt config --set-clickhouse <Clickhouse-url>
OR
create $HOME/config/config.yaml and provide the details
for example:
ch_conn: http://localhost:9000?username=admin&password=admin
qt_conn: http://localhost:8080 `)
return
}
// parsing the clickhouse url
dsnURL, err := url.Parse(Config.ClickHouseUrl)
if err != nil {
logger.Println(err)
}

options := &clickhouse.Options{
Addr: []string{dsnURL.Host},
}
if dsnURL.Query().Get("username") == "" || dsnURL.Query().Get("password") == "" {
logger.Println("url query has credentials missing")
}
if dsnURL.Query().Get("username") != "" {
auth := clickhouse.Auth{
Database: "signoz_traces",
Username: dsnURL.Query().Get("username"),
Password: dsnURL.Query().Get("password"),
}
options.Auth = auth
}

// creating a clickhouse connection
db, err := clickhouse.Open(options)
if err != nil {
logger.Println(err)
return
}
// closing the clickhouse connection at the end
defer db.Close()
// checking the clickhouse connection with a ping
err = db.Ping(context.Background())
if err != nil {
logger.Println(err)
}
// we query the database and print the details
query := "SELECT * FROM signoz_traces.repo WHERE name = ?"
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
err = db.Select(ctx, &result, query, reponame)
if err != nil {
logger.Println("Unable to query the database", err)
}

if Config.QualityTraceUrl == "" {
log.Println(`Please set the Quality Trace url using this command:
qt config --set-server <Quality-Trace-url>
OR
create $HOME/config/config.yaml and provide the details
for example:
CH_CONN: http://localhost:9000?username=admin&password=admin
QT_CONN: http://localhost:8080 `)
return
}

jsonData, err := json.Marshal(result[0])
if err != nil {
logger.Println("unable to marshal the data:", err)
}

path := fmt.Sprintf("%s/dryRun/", Config.QualityTraceUrl)
resp, err := http.Post(path, "application/json",
bytes.NewBuffer(jsonData))

if err != nil {
logger.Println(err)
return
}

defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
logger.Println("unable to read the response body: ", err)
return
}
strBody := string(body)
statusStr := "Fetching Data..."
lastIdx := strings.LastIndex(strBody, statusStr)
jsonBody := strBody[lastIdx+len(statusStr)+2 : len(strBody)-2]
data := AssertionData{}
json.Unmarshal([]byte(jsonBody), &data)
generateAssertions(data)
},
}

type AssertionData struct {
Columns []string `json:"columns"`
Events [][]interface{} `json:"events"`
}

func init() {
repoCmd.AddCommand(generateAssertionCmd)
}

func generateAssertions(data AssertionData) {
assertionFieldValueMap := map[string]string{}
for _, event := range data.Events {
assertionFields := map[int]string{}
// assertion fields
for idx, v := range event[7].([]interface{}) {
assertionFields[idx] = v.(string)
}
// assertion values
for idx, v := range event[8].([]interface{}) {
if field, ok := assertionFields[idx]; ok {
assertionFieldValueMap[field] = v.(string)
}
}
}
fmt.Printf("\n assertionFieldValueMap %v", assertionFieldValueMap)
GenerateYaml(assertionFieldValueMap)
}
10 changes: 9 additions & 1 deletion cli/cmd/repo_dryrun.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"log"
"net/http"
"net/url"
"strings"
"time"

clickhouse "github.com/ClickHouse/clickhouse-go/v2"
Expand Down Expand Up @@ -101,7 +102,14 @@ var repoDryRunCmd = &cobra.Command{
if err != nil {
logger.Println("unable to read the response body: ", err)
}
fmt.Println(string(body))
strBody := string(body)
statusStr := "Fetching Data..."
lastIdx := strings.LastIndex(strBody, statusStr)
jsonBody := strBody[lastIdx+len(statusStr)+2 : len(strBody)-2]
data := AssertionData{}
json.Unmarshal([]byte(jsonBody), &data)
generateAssertions(data)
fmt.Println(strBody)
},
}

Expand Down
45 changes: 45 additions & 0 deletions cli/cmd/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package cmd

import (
"fmt"
"gopkg.in/yaml.v3"
"io/ioutil"
"os"
"path"
"path/filepath"
"time"

log "github.com/sirupsen/logrus"
)

func GenerateYaml(values map[string]string) {
fmt.Println("\n Generating assertions yaml file")
wd, err := os.Getwd()
if err != nil {
log.Fatalf("error occured while getting working dir %v", err)
}
parentDir := filepath.Dir(wd)
assertionsDir := path.Join(parentDir, "generatedAssertionFiles")
os.Mkdir(assertionsDir, 0777)
fileName := fmt.Sprintf("assertions-%v.yaml", time.Now().Format(time.RFC822))
filePath := path.Join(assertionsDir, fileName)
var assertions []string
for key, value := range values {
kv := fmt.Sprintf("%s = %s", key, value)
assertions = append(assertions, kv)
}
assertVals := map[string][]string{"spec": assertions}

data, err := yaml.Marshal(&assertVals)

if err != nil {
log.Fatal(err)
}
err = ioutil.WriteFile(filePath, data, 0666)

if err != nil {
log.Fatal(err)
}

fmt.Printf("\n assertions yaml file created succesfully at path: %v", filePath)
}
23 changes: 23 additions & 0 deletions generatedAssertionFiles/assertions-07 May 23 11:21 IST.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
spec:
- db.statement = INSERT INTO `books` (`title`,`author`) VALUES ("foo","bar")
- http.route = /books
- http.status_code = 200
- http.user_agent = Go-http-client/1.1
- net.host.name = localhost
- http.request_content_length = 34
- http.method = POST
- db.rows_affected = 1
- net.peer.ip = 127.0.0.1
- service.name = goapp
- signoz.collector.id = 2ea75c7d-640a-4e91-b7a1-cbe464e02cac
- db.sql.table = books
- http.server_name = goapp
- library.language = go
- http.host = localhost:8090
- http.target = /books
- net.host.port = 8090
- net.peer.port = 40148
- http.scheme = http
- db.system = sqlite
- net.transport = ip_tcp
- http.flavor = 1.1