-
Notifications
You must be signed in to change notification settings - Fork 31
/
Copy pathmockserver.go
155 lines (127 loc) · 3.81 KB
/
mockserver.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
//
// SPDX-License-Identifier: Apache-2.0
package mock
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"os/signal"
"strings"
compute "google.golang.org/api/compute/v1"
)
// Instances stores and manages the instances during create,delete and list calls
var Instances []*compute.Instance
var singleConnHandler = make(chan struct{})
type httpHandler struct {
}
func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
//opType := decodeOperationType(r)
w.Header().Set("Content-Type", "application/json")
switch r.Method {
case "POST":
handleCreate(w, r)
case "GET":
handleList(w, r)
case "DELETE":
handleDelete(w, r)
}
}
// NewMockServer creates an http server to mock the gcp compute api
func NewMockServer() {
var srv = http.Server{
Addr: ":6666",
Handler: new(httpHandler),
}
//http.HandleFunc("/", handler)
go handleShutdown(&srv)
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
fmt.Printf("Failed to shutdown server %v", err)
}
<-singleConnHandler
}
func handleShutdown(srv *http.Server) {
shutDownSignal := make(chan os.Signal, 1)
signal.Notify(shutDownSignal, os.Interrupt)
<-shutDownSignal
if err := srv.Shutdown(context.Background()); err != nil {
fmt.Printf("HTTP server Shutdown: %v", err)
}
close(singleConnHandler)
}
/*
1. Extract the method from the Request to delegat to the correct handler
2. Extract the instance name which has the test sceanrio for which response needs to be formed
3. Create a response object according to the call
4. Prepare response.body with the json structure expected by the googe-api-go-client for compute
*/
func decodeOperationType(r *http.Request, index int) string {
opTypes := strings.Split(r.URL.Path, "/")
return opTypes[len(opTypes)-index]
}
func handleCreate(w http.ResponseWriter, r *http.Request) {
if decodeOperationType(r, 2) == "invalid post" {
http.Error(w, fmt.Sprint("Invalid post zone"), http.StatusBadRequest)
return
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
fmt.Println("Error in reading request body", err)
}
var instance *compute.Instance
err = json.Unmarshal(body, &instance)
if err != nil {
fmt.Println("Error in unmarshalling request body", err)
}
operation := compute.Operation{
Status: "RUNNING",
OperationType: "insert",
Kind: "compute#operation",
}
Instances = append(Instances, instance)
json.NewEncoder(w).Encode(operation)
}
func handleList(w http.ResponseWriter, r *http.Request) {
//error mock handling for create/delete calls
if decodeOperationType(r, 3) == "invalid list" {
http.Error(w, fmt.Sprint("Invalid list zone"), http.StatusBadRequest)
return
}
//error mock handling for listMachines call
if decodeOperationType(r, 2) == "invalid list" {
http.Error(w, fmt.Sprint("Invalid list zone"), http.StatusBadRequest)
return
}
// operation call is made for wait loop to let the create/delete operation to complete
if decodeOperationType(r, 2) == "operations" {
operation := compute.Operation{
Status: "DONE",
OperationType: "insert",
Kind: "compute#operation",
}
json.NewEncoder(w).Encode(operation)
} else { // this is the regular list call handling for VM
instances := compute.InstanceList{
Items: Instances,
}
json.NewEncoder(w).Encode(instances)
}
}
func handleDelete(w http.ResponseWriter, r *http.Request) {
if decodeOperationType(r, 3) == "invalid post" {
http.Error(w, fmt.Sprint("Invalid post zone"), http.StatusBadRequest)
return
}
if decodeOperationType(r, 1) == "reset-machine-count" {
Instances = nil
}
operation := compute.Operation{
Status: "RUNNING",
OperationType: "delete",
Kind: "compute#operation",
}
json.NewEncoder(w).Encode(operation)
}