PageRenderTime 57ms CodeModel.GetById 12ms app.highlight 41ms RepoModel.GetById 1ms app.codeStats 0ms

/client.go

https://gitlab.com/cosman2001/shmocklib
Go | 219 lines | 175 code | 18 blank | 26 comment | 38 complexity | f9c9129b98879f4cbc85ff8d48070521 MD5 | raw file
  1package shmocklib
  2
  3import (
  4	"bytes"
  5	"encoding/json"
  6	"fmt"
  7	"io/ioutil"
  8	"log"
  9	"net/http"
 10	"os"
 11	"os/exec"
 12	"path"
 13	"strings"
 14	"syscall"
 15)
 16
 17func GetCommandList() []string {
 18	// path is normally reserved for File related things, but since its unix this will also work on url schemes
 19	endpoint := GenerateEndpoint("", "")
 20	jsondata := Get(endpoint)
 21	commands := []string{}
 22	// render json to object
 23
 24	de_err := json.Unmarshal(jsondata, &commands)
 25	check(de_err)
 26	return commands
 27}
 28func Get(url string) []byte {
 29	client := &http.Client{}
 30	req, err := http.NewRequest("GET", url, nil)
 31	check(err)
 32	req.Header.Add("X-Shmock-Namespace", namespace)
 33	response, err := client.Do(req)
 34	if err != nil {
 35		log.Fatal(err)
 36		os.Exit(1)
 37	} else {
 38		defer response.Body.Close()
 39		contents, err := ioutil.ReadAll(response.Body)
 40		// Check for 404 error, return command not found
 41		if err != nil {
 42			log.Fatal(err)
 43		}
 44		return contents
 45	}
 46	return nil
 47}
 48func DoGet(url string) CommandResponse {
 49	contents := Get(url)
 50	cmd := renderJson(contents)
 51	return cmd
 52}
 53func DoPost(url string, json_body []byte, namespace string) {
 54	client := &http.Client{}
 55	req, err := http.NewRequest("POST", url, bytes.NewBuffer(json_body))
 56
 57	if namespace != "" {
 58		req.Header.Set("X-Command-Namespace", namespace)
 59	}
 60	req.Header.Set("Content-Type", "application/json")
 61
 62	resp, err := client.Do(req)
 63	if err != nil {
 64		panic(err)
 65	}
 66	defer resp.Body.Close()
 67
 68	fmt.Println("response Status:", resp.Status)
 69	fmt.Println("response Headers:", resp.Header)
 70	body, _ := ioutil.ReadAll(resp.Body)
 71	fmt.Println("response Body:", string(body))
 72
 73}
 74func DoPut(url string) {
 75	client := &http.Client{}
 76	request, err := http.NewRequest("PUT", url, strings.NewReader("<golang>really</golang>"))
 77	request.SetBasicAuth("admin", "admin")
 78	request.ContentLength = 23
 79	response, err := client.Do(request)
 80	if err != nil {
 81		log.Fatal(err)
 82	} else {
 83		defer response.Body.Close()
 84		contents, err := ioutil.ReadAll(response.Body)
 85		if err != nil {
 86			log.Fatal(err)
 87		}
 88		fmt.Println("The calculated length is:", len(string(contents)), "for the url:", url)
 89		fmt.Println("   ", response.StatusCode)
 90		hdr := response.Header
 91		for key, value := range hdr {
 92			fmt.Println("   ", key, ":", value)
 93		}
 94		fmt.Println(contents)
 95	}
 96}
 97
 98// generates a valid http endpoint
 99// uses SHMOCK_SERVER_URL to determine endpoint
100// or uses SHMOCK_SERVER_IP and SHMOCK_SERVER_PORT
101// or falls back to localhost:3000 as endpoint
102func GenerateEndpoint(command_name string, args_hash string) string {
103	server_url := os.Getenv("SHMOCK_SERVER_URL")
104	if server_url == "" {
105		ip := os.Getenv("SHMOCK_SERVER_IP")
106		port := os.Getenv("SHMOCK_SERVER_PORT")
107		if ip == "" || port == "" {
108			server_url = "http://localhost:3000"
109		}
110		server_url = fmt.Sprintf("http://%s:%s", ip, port)
111	}
112	return fmt.Sprintf("%s/%s", path.Join(server_url, "commands", command_name, args_hash))
113}
114
115// write the map output to a file
116// if a file already exists with a map inside, read the contents first and then merge the contents and overwrite the file
117func MergeToCaptureFile(filepath string, m map[string]CommandResponse) {
118	if _, err := os.Stat(filepath); os.IsNotExist(err) {
119		// file does not exist, no need to merge
120		createTemplatePath(filepath)
121	} else {
122		// file already exists we need to read in the data and then merge the two together
123		prev := GenerateResponseMapFromFile(filepath)
124		for k, v := range prev {
125			m[k] = v
126		}
127	}
128	b, err := json.MarshalIndent(m, "", "   ")
129	if err != nil {
130		log.Fatalf("error encoding command %v", err)
131	}
132	err = ioutil.WriteFile(filepath, b, 0644)
133	check(err)
134	log.Printf("Wrote to file: %s", filepath)
135}
136func GetCommand(command_name string, args_hash string) {
137	// path is normally reserved for File related things, but since its unix this will also work on url schemes
138	endpoint := GenerateEndpoint(command_name, args_hash)
139	cmd := DoGet(endpoint)
140	PrintToConsole(cmd)
141}
142
143// run the command on the os and capture the output, return a CommandResponse Object
144func CaptureCommand(args []string) CommandResponse {
145	command := args[0]
146	args = args[1:]
147	log.Printf("Command: %s %s", command, args)
148	var exitcode = 0
149	cmd := exec.Command(command, args...)
150	var stdout bytes.Buffer
151	var stderr bytes.Buffer
152	cmd.Stdout = &stdout
153	cmd.Stderr = &stderr
154
155	if err := cmd.Start(); err != nil {
156		log.Fatalf("cmd.Start: %v")
157	}
158
159	if err := cmd.Wait(); err != nil {
160		if exiterr, ok := err.(*exec.ExitError); ok {
161			// The program has exited with an exit code != 0
162			// There is no plattform independent way to retrieve
163			// the exit code, but the following will work on Unix
164			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
165				// for some odd reason this is output exit status 1
166				exitcode = status.ExitStatus()
167			}
168		} else {
169			log.Fatalf("cmd.Wait: %v", err)
170		}
171	}
172
173	//usertime := cmd.ProcessState.UserTime()
174	//fmt.Printf("Milli [%v]", usertime.Seconds())
175
176	log.Printf("Exit Status: %d", exitcode)
177	// store the original command call in stdin
178	stdin := append([]string{command}, args...)
179	command_response := CommandResponse{Stdout: stdout.String(),
180		Stderr:   stderr.String(),
181		Exitcode: exitcode,
182		Delay:    0,
183		Stdin:    strings.Join(stdin, " "),
184	}
185	return command_response
186}
187func renderJson(jsondata []byte) CommandResponse {
188	res := &CommandResponse{}
189	// render json to object
190
191	de_err := json.Unmarshal(jsondata, &res)
192
193	if de_err != nil {
194		//return nil if not found
195		fmt.Println(string(jsondata))
196		//panic(de_err)
197		res.Exitcode = 1
198		res.Stdout = "Invalid Json in Command Response"
199	}
200	return *res
201}
202
203// Creates the given path, if path has an extension it gets the base name of the file and generates that path
204// The template path is where we store all the shmock response json files
205func createTemplatePath(filepath string) {
206	filepath = path.Dir(filepath)
207	err := os.MkdirAll(filepath, 0744)
208	check(err)
209}
210
211// dumps the cmd and exit status to the console then exits
212func PrintToConsole(command CommandResponse) {
213	if command.Exitcode == 0 {
214		fmt.Print(command.Stdout)
215	} else {
216		fmt.Println(command.Stderr)
217	}
218	os.Exit(command.Exitcode)
219}