mirror of
https://github.com/redhat-developer/odo.git
synced 2025-10-19 03:06:19 +03:00
E2e scenario 3 (#6073)
* add e2e test for binding Signed-off-by: anandrkskd <anandrkskd@gmail.com> * fails on testing binding's Signed-off-by: anandrkskd <anandrkskd@gmail.com> * update e2e test Signed-off-by: anandrkskd <anandrkskd@gmail.com> * remove FIt Signed-off-by: anandrkskd <anandrkskd@gmail.com> * incorporate requested changes Signed-off-by: anandrkskd <anandrkskd@gmail.com> * incorporate requested changes Signed-off-by: anandrkskd <anandrkskd@gmail.com> * dont run go sec on example directory Signed-off-by: anandrkskd <anandrkskd@gmail.com> * fix flaky behaviour Signed-off-by: anandrkskd <anandrkskd@gmail.com> * fix flaky behaviour Signed-off-by: anandrkskd <anandrkskd@gmail.com> * nit: cleanup Signed-off-by: anandrkskd <anandrkskd@gmail.com> * Apply suggestions from code review Signed-off-by: anandrkskd <anandrkskd@gmail.com> Co-authored-by: Armel Soro <armel@rm3l.org>
This commit is contained in:
committed by
GitHub
parent
c9875200ed
commit
6172a16fc7
2
Makefile
2
Makefile
@@ -111,7 +111,7 @@ vet:
|
|||||||
|
|
||||||
.PHONY: sec
|
.PHONY: sec
|
||||||
sec:
|
sec:
|
||||||
go run $(COMMON_GOFLAGS) github.com/securego/gosec/v2/cmd/gosec -severity medium -confidence medium -exclude G304,G204,G107 -quiet ./tests/...
|
go run $(COMMON_GOFLAGS) github.com/securego/gosec/v2/cmd/gosec -severity medium -confidence medium -exclude G304,G204,G107 -quiet ./tests/integration/... ./tests/helper... ./tests/e2escenarios/...
|
||||||
go run $(COMMON_GOFLAGS) github.com/securego/gosec/v2/cmd/gosec -severity medium -confidence medium -exclude G304,G204 -quiet ./cmd/... ./pkg/...
|
go run $(COMMON_GOFLAGS) github.com/securego/gosec/v2/cmd/gosec -severity medium -confidence medium -exclude G304,G204 -quiet ./cmd/... ./pkg/...
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
//go:build linux || darwin || dragonfly || solaris || openbsd || netbsd || freebsd
|
|
||||||
// +build linux darwin dragonfly solaris openbsd netbsd freebsd
|
|
||||||
|
|
||||||
package e2escenarios
|
package e2escenarios
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -29,7 +28,10 @@ var _ = Describe("E2E Test", func() {
|
|||||||
checkIfDevEnvIsUp := func(url, assertString string) {
|
checkIfDevEnvIsUp := func(url, assertString string) {
|
||||||
Eventually(func() string {
|
Eventually(func() string {
|
||||||
resp, err := http.Get(fmt.Sprintf("http://%s", url))
|
resp, err := http.Get(fmt.Sprintf("http://%s", url))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
if err != nil {
|
||||||
|
fmt.Fprintf(GinkgoWriter, "error while trying to GET %q: %v\n", url, err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
body, _ := io.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
@@ -57,10 +59,10 @@ var _ = Describe("E2E Test", func() {
|
|||||||
helper.SendLine(ctx, "JavaScript")
|
helper.SendLine(ctx, "JavaScript")
|
||||||
|
|
||||||
helper.ExpectString(ctx, "Select project type")
|
helper.ExpectString(ctx, "Select project type")
|
||||||
helper.SendLine(ctx, "Node.js\n")
|
helper.SendLine(ctx, "Node.js")
|
||||||
|
|
||||||
helper.ExpectString(ctx, "Which starter project do you want to use")
|
helper.ExpectString(ctx, "Which starter project do you want to use")
|
||||||
helper.SendLine(ctx, "nodejs-starter\n")
|
helper.SendLine(ctx, "nodejs-starter")
|
||||||
|
|
||||||
helper.ExpectString(ctx, "Enter component name")
|
helper.ExpectString(ctx, "Enter component name")
|
||||||
helper.SendLine(ctx, componentName)
|
helper.SendLine(ctx, componentName)
|
||||||
@@ -173,11 +175,11 @@ var _ = Describe("E2E Test", func() {
|
|||||||
helper.ExpectString(ctx, "Project type: Node.js")
|
helper.ExpectString(ctx, "Project type: Node.js")
|
||||||
helper.ExpectString(ctx, "Is this correct")
|
helper.ExpectString(ctx, "Is this correct")
|
||||||
|
|
||||||
helper.SendLine(ctx, "\n")
|
helper.SendLine(ctx, "")
|
||||||
|
|
||||||
helper.ExpectString(ctx, "Select container for which you want to change configuration?")
|
helper.ExpectString(ctx, "Select container for which you want to change configuration?")
|
||||||
|
|
||||||
helper.SendLine(ctx, "\n")
|
helper.SendLine(ctx, "")
|
||||||
|
|
||||||
helper.ExpectString(ctx, "Enter component name")
|
helper.ExpectString(ctx, "Enter component name")
|
||||||
|
|
||||||
@@ -270,4 +272,137 @@ var _ = Describe("E2E Test", func() {
|
|||||||
Eventually(string(commonVar.CliRunner.Run(getSVCArgs...).Out.Contents()), 60, 3).ShouldNot(ContainSubstring(serviceName))
|
Eventually(string(commonVar.CliRunner.Run(getSVCArgs...).Out.Contents()), 60, 3).ShouldNot(ContainSubstring(serviceName))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Context("starting with non-empty Directory add Binding", func() {
|
||||||
|
componentName := helper.RandString(6)
|
||||||
|
|
||||||
|
sendDataEntry := func(url string) map[string]interface{} {
|
||||||
|
values := map[string]interface{}{"name": "joe",
|
||||||
|
"location": "tokyo",
|
||||||
|
"age": 23,
|
||||||
|
}
|
||||||
|
json_data, err := json.Marshal(values)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
resp, err := http.Post(fmt.Sprintf("http://%s/api/newuser", url), "application/json", bytes.NewBuffer(json_data))
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
var res map[string]interface{}
|
||||||
|
err = json.NewDecoder(resp.Body).Decode(&res)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
receiveData := func(url string) (string, error) {
|
||||||
|
resp, err := http.Get(fmt.Sprintf("http://%s", url))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
return string(body), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = BeforeEach(func() {
|
||||||
|
commonVar.CliRunner.EnsureOperatorIsInstalled("service-binding-operator")
|
||||||
|
commonVar.CliRunner.EnsureOperatorIsInstalled("cloud-native-postgresql")
|
||||||
|
Eventually(func() string {
|
||||||
|
out, _ := commonVar.CliRunner.GetBindableKinds()
|
||||||
|
return out
|
||||||
|
}, 120, 3).Should(ContainSubstring("Cluster"))
|
||||||
|
helper.Chdir(commonVar.Context)
|
||||||
|
helper.CopyExample(filepath.Join("source", "devfiles", "go"), commonVar.Context)
|
||||||
|
addBindableKind := commonVar.CliRunner.Run("apply", "-f", helper.GetExamplePath("source", "devfiles", "go", "cluster.yaml"))
|
||||||
|
Expect(addBindableKind.ExitCode()).To(BeEquivalentTo(0))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should verify developer workflow of using binding as env in innerloop", func() {
|
||||||
|
bindingName := helper.RandString(6)
|
||||||
|
|
||||||
|
command := []string{"odo", "init"}
|
||||||
|
_, err := helper.RunInteractive(command, nil, func(ctx helper.InteractiveContext) {
|
||||||
|
|
||||||
|
// helper.ExpectString(ctx, "Based on the files in the current directory odo detected")
|
||||||
|
helper.ExpectString(ctx, "Language: Go")
|
||||||
|
helper.ExpectString(ctx, "Project type: Go")
|
||||||
|
helper.ExpectString(ctx, "Is this correct")
|
||||||
|
|
||||||
|
helper.SendLine(ctx, "")
|
||||||
|
|
||||||
|
helper.ExpectString(ctx, "Select container for which you want to change configuration?")
|
||||||
|
|
||||||
|
helper.SendLine(ctx, "")
|
||||||
|
|
||||||
|
helper.ExpectString(ctx, "Enter component name")
|
||||||
|
|
||||||
|
helper.SendLine(ctx, componentName)
|
||||||
|
|
||||||
|
helper.ExpectString(ctx, "Your new component '"+componentName+"' is ready in the current directory")
|
||||||
|
|
||||||
|
})
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(helper.ListFilesInDir(commonVar.Context)).To(ContainElement("devfile.yaml"))
|
||||||
|
|
||||||
|
// // "execute odo dev and add changes to application"
|
||||||
|
var devSession helper.DevSession
|
||||||
|
var ports map[string]string
|
||||||
|
|
||||||
|
devSession, _, _, ports, err = helper.StartDevMode(helper.DevSessionOpts{})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
// "send data"
|
||||||
|
_, err = receiveData(fmt.Sprintf(ports["8080"] + "/api/user"))
|
||||||
|
Expect(err).ToNot(BeNil()) // should fail as application is not connected to DB
|
||||||
|
|
||||||
|
//add binding information (binding as ENV)
|
||||||
|
helper.Cmd("odo", "add", "binding", "--name", bindingName, "--service", "cluster-example-initdb", "--bind-as-files=false").ShouldPass()
|
||||||
|
|
||||||
|
// Get new random port after restart
|
||||||
|
Eventually(func() map[string]string {
|
||||||
|
_, _, ports, err = devSession.GetInfo()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
return ports
|
||||||
|
}, 180, 10).ShouldNot(BeEmpty())
|
||||||
|
|
||||||
|
// "send data"
|
||||||
|
data := sendDataEntry(ports["8080"])
|
||||||
|
Expect(data["message"]).To(Equal("User created successfully"))
|
||||||
|
|
||||||
|
// "get all data"
|
||||||
|
rec, err := receiveData(fmt.Sprintf(ports["8080"] + "/api/user"))
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
helper.MatchAllInOutput(rec, []string{"id", "1", "name", "joe", "location", "tokyo", "age", "23"})
|
||||||
|
|
||||||
|
// check odo describe to check for env
|
||||||
|
stdout := helper.Cmd("odo", "describe", "binding").ShouldPass().Out()
|
||||||
|
helper.MatchAllInOutput(stdout, []string{"Available binding information:", "CLUSTER_HOST", "CLUSTER_PASSWORD", "CLUSTER_USERNAME"})
|
||||||
|
|
||||||
|
// "running odo list"
|
||||||
|
stdout = helper.Cmd("odo", "list").ShouldPass().Out()
|
||||||
|
helper.MatchAllInOutput(stdout, []string{componentName, "Go", "Dev", bindingName})
|
||||||
|
|
||||||
|
// "exit dev mode"
|
||||||
|
devSession.Stop()
|
||||||
|
devSession.WaitEnd()
|
||||||
|
|
||||||
|
// remove bindings and check devfile to not contain binding info
|
||||||
|
// TODO: move `remove binding` inside devsession after https://github.com/redhat-developer/odo/issues/6101 is fixed
|
||||||
|
helper.Cmd("odo", "remove", "binding", "--name", bindingName).ShouldPass()
|
||||||
|
|
||||||
|
devSession, _, _, _, err = helper.StartDevMode(helper.DevSessionOpts{})
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
stdout = helper.Cmd("odo", "describe", "binding").ShouldPass().Out()
|
||||||
|
Expect(stdout).To(ContainSubstring("No ServiceBinding used by the current component"))
|
||||||
|
|
||||||
|
devSession.Stop()
|
||||||
|
devSession.WaitEnd()
|
||||||
|
|
||||||
|
// all resources should be deleted from the namespace
|
||||||
|
services := commonVar.CliRunner.GetServices(commonVar.Project)
|
||||||
|
Expect(services).NotTo(ContainSubstring(componentName))
|
||||||
|
pvcs := commonVar.CliRunner.GetAllPVCNames(commonVar.Project)
|
||||||
|
Expect(pvcs).NotTo(ContainElement(componentName)) //To(Not(ContainSubstring(componentName)))
|
||||||
|
pods := commonVar.CliRunner.GetAllPodNames(commonVar.Project)
|
||||||
|
Expect(pods).NotTo(ContainElement(componentName))
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
34
tests/examples/source/devfiles/go/cluster.yaml
Normal file
34
tests/examples/source/devfiles/go/cluster.yaml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
apiVersion: postgresql.k8s.enterprisedb.io/v1
|
||||||
|
kind: Cluster
|
||||||
|
metadata:
|
||||||
|
name: cluster-example-initdb
|
||||||
|
spec:
|
||||||
|
instances: 1
|
||||||
|
bootstrap:
|
||||||
|
initdb:
|
||||||
|
database: appdb
|
||||||
|
owner: appuser
|
||||||
|
secret:
|
||||||
|
name: appuser-secret
|
||||||
|
postInitApplicationSQL:
|
||||||
|
- create table users (userid SERIAL PRIMARY KEY, name TEXT, age INT, location TEXT)
|
||||||
|
storage:
|
||||||
|
size: 1Gi
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
stringData:
|
||||||
|
username: appuser
|
||||||
|
password: test-12password!
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: appuser-secret
|
||||||
|
type: kubernetes.io/basic-auth
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
stringData:
|
||||||
|
username: appuser
|
||||||
|
password: test-12password!
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: cluster-example-initdb-appuser
|
||||||
|
type: kubernetes.io/basic-auth
|
||||||
7
tests/examples/source/devfiles/go/go.mod
Normal file
7
tests/examples/source/devfiles/go/go.mod
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
module go-postgres
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/gorilla/mux v1.7.4
|
||||||
|
github.com/joho/godotenv v1.3.0
|
||||||
|
github.com/lib/pq v1.3.0
|
||||||
|
)
|
||||||
6
tests/examples/source/devfiles/go/go.sum
Normal file
6
tests/examples/source/devfiles/go/go.sum
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc=
|
||||||
|
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||||
|
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||||
|
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||||
|
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
|
||||||
|
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
15
tests/examples/source/devfiles/go/main.go
Normal file
15
tests/examples/source/devfiles/go/main.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go-postgres/router"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
r := router.Router()
|
||||||
|
fmt.Println("Starting server on the port 8080...")
|
||||||
|
|
||||||
|
log.Fatal(http.ListenAndServe(":8080", r))
|
||||||
|
}
|
||||||
348
tests/examples/source/devfiles/go/middleware/handlers.go
Normal file
348
tests/examples/source/devfiles/go/middleware/handlers.go
Normal file
@@ -0,0 +1,348 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"go-postgres/models"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
|
_ "github.com/lib/pq"
|
||||||
|
)
|
||||||
|
|
||||||
|
// response format
|
||||||
|
type response struct {
|
||||||
|
ID int64 `json:"id,omitempty"`
|
||||||
|
Message string `json:"message,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// create connection with postgres db
|
||||||
|
func createConnection() *sql.DB {
|
||||||
|
|
||||||
|
// collect values form env
|
||||||
|
connStr := "postgres://" + os.Getenv("CLUSTER_USERNAME") + ":" + os.Getenv("CLUSTER_PASSWORD") + "@" + os.Getenv("CLUSTER_HOST") + "/" + os.Getenv("CLUSTER_DATABASE") + "?sslmode=disable"
|
||||||
|
|
||||||
|
// Open the connection
|
||||||
|
db, err := sql.Open("postgres", connStr)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the connection
|
||||||
|
err = db.Ping()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Successfully connected!")
|
||||||
|
// return the connection
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateUser create a user in the postgres db
|
||||||
|
func CreateUser(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
// create an empty user of type models.User
|
||||||
|
var user models.User
|
||||||
|
|
||||||
|
// decode the json request to user
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&user)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to decode the request body. %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// call insert user function and pass the user
|
||||||
|
insertID := insertUser(user)
|
||||||
|
|
||||||
|
// format a response object
|
||||||
|
res := response{
|
||||||
|
ID: insertID,
|
||||||
|
Message: "User created successfully",
|
||||||
|
}
|
||||||
|
|
||||||
|
// send the response
|
||||||
|
json.NewEncoder(w).Encode(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUser will return a single user by its id
|
||||||
|
func GetUser(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// get the userid from the request params, key is "id"
|
||||||
|
params := mux.Vars(r)
|
||||||
|
|
||||||
|
// convert the id type from string to int
|
||||||
|
id, err := strconv.Atoi(params["id"])
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to convert the string into int. %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// call the getUser function with user id to retrieve a single user
|
||||||
|
user, err := getUser(int64(id))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to get user. %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// send the response
|
||||||
|
json.NewEncoder(w).Encode(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllUser will return all the users
|
||||||
|
func GetAllUser(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
// get all the users in the db
|
||||||
|
users, err := getAllUsers()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to get all user. %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// send all the users as response
|
||||||
|
json.NewEncoder(w).Encode(users)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUser update user's detail in the postgres db
|
||||||
|
func UpdateUser(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
// get the userid from the request params, key is "id"
|
||||||
|
params := mux.Vars(r)
|
||||||
|
|
||||||
|
// convert the id type from string to int
|
||||||
|
id, err := strconv.Atoi(params["id"])
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to convert the string into int. %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create an empty user of type models.User
|
||||||
|
var user models.User
|
||||||
|
|
||||||
|
// decode the json request to user
|
||||||
|
err = json.NewDecoder(r.Body).Decode(&user)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to decode the request body. %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// call update user to update the user
|
||||||
|
updatedRows := updateUser(int64(id), user)
|
||||||
|
|
||||||
|
// format the message string
|
||||||
|
msg := fmt.Sprintf("User updated successfully. Total rows/record affected %v", updatedRows)
|
||||||
|
|
||||||
|
// format the response message
|
||||||
|
res := response{
|
||||||
|
ID: int64(id),
|
||||||
|
Message: msg,
|
||||||
|
}
|
||||||
|
|
||||||
|
// send the response
|
||||||
|
json.NewEncoder(w).Encode(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteUser delete user's detail in the postgres db
|
||||||
|
func DeleteUser(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
// get the userid from the request params, key is "id"
|
||||||
|
params := mux.Vars(r)
|
||||||
|
|
||||||
|
// convert the id in string to int
|
||||||
|
id, err := strconv.Atoi(params["id"])
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to convert the string into int. %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// call the deleteUser, convert the int to int64
|
||||||
|
deletedRows := deleteUser(int64(id))
|
||||||
|
|
||||||
|
// format the message string
|
||||||
|
msg := fmt.Sprintf("User updated successfully. Total rows/record affected %v", deletedRows)
|
||||||
|
|
||||||
|
// format the reponse message
|
||||||
|
res := response{
|
||||||
|
ID: int64(id),
|
||||||
|
Message: msg,
|
||||||
|
}
|
||||||
|
|
||||||
|
// send the response
|
||||||
|
json.NewEncoder(w).Encode(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------- handler functions ----------------
|
||||||
|
// insert one user in the DB
|
||||||
|
func insertUser(user models.User) int64 {
|
||||||
|
|
||||||
|
// create the postgres db connection
|
||||||
|
db := createConnection()
|
||||||
|
|
||||||
|
// close the db connection
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
// create the insert sql query
|
||||||
|
// returning userid will return the id of the inserted user
|
||||||
|
sqlStatement := `INSERT INTO users (name, location, age) VALUES ($1, $2, $3) RETURNING userid`
|
||||||
|
|
||||||
|
// the inserted id will store in this id
|
||||||
|
var id int64
|
||||||
|
|
||||||
|
// execute the sql statement
|
||||||
|
// Scan function will save the insert id in the id
|
||||||
|
err := db.QueryRow(sqlStatement, user.Name, user.Location, user.Age).Scan(&id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to execute the query. %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Inserted a single record %v", id)
|
||||||
|
|
||||||
|
// return the inserted id
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
// get one user from the DB by its userid
|
||||||
|
func getUser(id int64) (models.User, error) {
|
||||||
|
// create the postgres db connection
|
||||||
|
db := createConnection()
|
||||||
|
|
||||||
|
// close the db connection
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
// create a user of models.User type
|
||||||
|
var user models.User
|
||||||
|
|
||||||
|
// create the select sql query
|
||||||
|
sqlStatement := `SELECT * FROM users WHERE userid=$1`
|
||||||
|
|
||||||
|
// execute the sql statement
|
||||||
|
row := db.QueryRow(sqlStatement, id)
|
||||||
|
|
||||||
|
// unmarshal the row object to user
|
||||||
|
err := row.Scan(&user.ID, &user.Name, &user.Age, &user.Location)
|
||||||
|
|
||||||
|
switch err {
|
||||||
|
case sql.ErrNoRows:
|
||||||
|
fmt.Println("No rows were returned!")
|
||||||
|
return user, nil
|
||||||
|
case nil:
|
||||||
|
return user, nil
|
||||||
|
default:
|
||||||
|
log.Fatalf("Unable to scan the row. %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// return empty user on error
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// get one user from the DB by its userid
|
||||||
|
func getAllUsers() ([]models.User, error) {
|
||||||
|
// create the postgres db connection
|
||||||
|
db := createConnection()
|
||||||
|
|
||||||
|
// close the db connection
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
var users []models.User
|
||||||
|
|
||||||
|
// create the select sql query
|
||||||
|
sqlStatement := `SELECT * FROM users`
|
||||||
|
|
||||||
|
// execute the sql statement
|
||||||
|
rows, err := db.Query(sqlStatement)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to execute the query. %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// close the statement
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
// iterate over the rows
|
||||||
|
for rows.Next() {
|
||||||
|
var user models.User
|
||||||
|
|
||||||
|
// unmarshal the row object to user
|
||||||
|
err = rows.Scan(&user.ID, &user.Name, &user.Age, &user.Location)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to scan the row. %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// append the user in the users slice
|
||||||
|
users = append(users, user)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// return empty user on error
|
||||||
|
return users, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update user in the DB
|
||||||
|
func updateUser(id int64, user models.User) int64 {
|
||||||
|
|
||||||
|
// create the postgres db connection
|
||||||
|
db := createConnection()
|
||||||
|
|
||||||
|
// close the db connection
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
// create the update sql query
|
||||||
|
sqlStatement := `UPDATE users SET name=$2, location=$3, age=$4 WHERE userid=$1`
|
||||||
|
|
||||||
|
// execute the sql statement
|
||||||
|
res, err := db.Exec(sqlStatement, id, user.Name, user.Location, user.Age)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to execute the query. %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check how many rows affected
|
||||||
|
rowsAffected, err := res.RowsAffected()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error while checking the affected rows. %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Total rows/record affected %v", rowsAffected)
|
||||||
|
|
||||||
|
return rowsAffected
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete user in the DB
|
||||||
|
func deleteUser(id int64) int64 {
|
||||||
|
|
||||||
|
// create the postgres db connection
|
||||||
|
db := createConnection()
|
||||||
|
|
||||||
|
// close the db connection
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
// create the delete sql query
|
||||||
|
sqlStatement := `DELETE FROM users WHERE userid=$1`
|
||||||
|
|
||||||
|
// execute the sql statement
|
||||||
|
res, err := db.Exec(sqlStatement, id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to execute the query. %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check how many rows affected
|
||||||
|
rowsAffected, err := res.RowsAffected()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error while checking the affected rows. %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Total rows/record affected %v", rowsAffected)
|
||||||
|
|
||||||
|
return rowsAffected
|
||||||
|
}
|
||||||
9
tests/examples/source/devfiles/go/models/models.go
Normal file
9
tests/examples/source/devfiles/go/models/models.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
// User schema of the user table
|
||||||
|
type User struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Location string `json:"location"`
|
||||||
|
Age int64 `json:"age"`
|
||||||
|
}
|
||||||
21
tests/examples/source/devfiles/go/router/router.go
Normal file
21
tests/examples/source/devfiles/go/router/router.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go-postgres/middleware"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Router is exported and used in main.go
|
||||||
|
func Router() *mux.Router {
|
||||||
|
|
||||||
|
router := mux.NewRouter()
|
||||||
|
|
||||||
|
router.HandleFunc("/api/user/{id}", middleware.GetUser).Methods("GET", "OPTIONS")
|
||||||
|
router.HandleFunc("/api/user", middleware.GetAllUser).Methods("GET", "OPTIONS")
|
||||||
|
router.HandleFunc("/api/newuser", middleware.CreateUser).Methods("POST", "OPTIONS")
|
||||||
|
router.HandleFunc("/api/user/{id}", middleware.UpdateUser).Methods("PUT", "OPTIONS")
|
||||||
|
router.HandleFunc("/api/deleteuser/{id}", middleware.DeleteUser).Methods("DELETE", "OPTIONS")
|
||||||
|
|
||||||
|
return router
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user