github.com/spinnaker/spin@v1.30.0/cmd/application/save_test.go (about)

     1  // Copyright (c) 2018, Google, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //   http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  //   Unless required by applicable law or agreed to in writing, software
    10  //   distributed under the License is distributed on an "AS IS" BASIS,
    11  //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  //   See the License for the specific language governing permissions and
    13  //   limitations under the License.
    14  
    15  package application
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"io"
    21  	"io/ioutil"
    22  	"net/http"
    23  	"net/http/httptest"
    24  	"os"
    25  	"strings"
    26  	"testing"
    27  
    28  	"github.com/spinnaker/spin/cmd"
    29  	"github.com/spinnaker/spin/util"
    30  )
    31  
    32  const (
    33  	NAME  = "app"
    34  	EMAIL = "appowner@spinnaker-test.net"
    35  )
    36  
    37  func TestApplicationSave_basic(t *testing.T) {
    38  	saveBuffer := new(bytes.Buffer)
    39  	ts := testGateAppSaveSuccess(saveBuffer)
    40  	defer ts.Close()
    41  
    42  	rootCmd, options := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard)
    43  	rootCmd.AddCommand(NewApplicationCmd(options))
    44  
    45  	args := []string{
    46  		"application", "save",
    47  		"--gate-endpoint=" + ts.URL,
    48  		"--application-name", NAME,
    49  		"--owner-email", EMAIL,
    50  		"--cloud-providers", "gce,kubernetes",
    51  	}
    52  	rootCmd.SetArgs(args)
    53  	err := rootCmd.Execute()
    54  	if err != nil {
    55  		t.Fatalf("Command failed with: %s", err)
    56  	}
    57  
    58  	expected := strings.TrimSpace(testAppTaskJsonStr)
    59  	recieved := saveBuffer.Bytes()
    60  	util.TestPrettyJsonDiff(t, "save request body", expected, recieved)
    61  }
    62  
    63  func TestApplicationSave_fail(t *testing.T) {
    64  	ts := testGateFail()
    65  	defer ts.Close()
    66  
    67  	rootCmd, options := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard)
    68  	rootCmd.AddCommand(NewApplicationCmd(options))
    69  
    70  	args := []string{
    71  		"application", "save",
    72  		"--application-name", NAME,
    73  		"--owner-email", EMAIL,
    74  		"--cloud-providers", "gce,kubernetes",
    75  		"--gate-endpoint=" + ts.URL,
    76  	}
    77  	rootCmd.SetArgs(args)
    78  	err := rootCmd.Execute()
    79  	if err == nil {
    80  		t.Fatalf("Command failed with: %s", err)
    81  	}
    82  }
    83  
    84  func TestApplicationSave_flags(t *testing.T) {
    85  	saveBuffer := new(bytes.Buffer)
    86  	ts := testGateAppSaveSuccess(saveBuffer)
    87  	defer ts.Close()
    88  
    89  	rootCmd, options := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard)
    90  	rootCmd.AddCommand(NewApplicationCmd(options))
    91  
    92  	args := []string{
    93  		"application", "save",
    94  		"--gate-endpoint=" + ts.URL,
    95  	}
    96  	rootCmd.SetArgs(args)
    97  	err := rootCmd.Execute()
    98  	if err == nil {
    99  		t.Fatalf("Command failed with: %s", err)
   100  	}
   101  
   102  	expected := ""
   103  	recieved := strings.TrimSpace(saveBuffer.String())
   104  	if expected != recieved {
   105  		t.Fatalf("Unexpected save request body:\n%s", recieved)
   106  	}
   107  }
   108  
   109  func TestApplicationSave_missingname(t *testing.T) {
   110  	saveBuffer := new(bytes.Buffer)
   111  	ts := testGateAppSaveSuccess(saveBuffer)
   112  	defer ts.Close()
   113  
   114  	rootCmd, options := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard)
   115  	rootCmd.AddCommand(NewApplicationCmd(options))
   116  
   117  	args := []string{
   118  		"application", "save",
   119  		"--owner-email", EMAIL,
   120  		"--cloud-providers", "gce,kubernetes",
   121  		"--gate-endpoint=" + ts.URL,
   122  	}
   123  	rootCmd.SetArgs(args)
   124  	err := rootCmd.Execute()
   125  	if err == nil {
   126  		t.Fatalf("Command failed with: %s", err)
   127  	}
   128  
   129  	expected := ""
   130  	recieved := strings.TrimSpace(saveBuffer.String())
   131  	if expected != recieved {
   132  		t.Fatalf("Unexpected save request body:\n%s", recieved)
   133  	}
   134  }
   135  
   136  func TestApplicationSave_missingemail(t *testing.T) {
   137  	saveBuffer := new(bytes.Buffer)
   138  	ts := testGateAppSaveSuccess(saveBuffer)
   139  	defer ts.Close()
   140  
   141  	rootCmd, options := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard)
   142  	rootCmd.AddCommand(NewApplicationCmd(options))
   143  
   144  	args := []string{
   145  		"application", "save",
   146  		"--application-name", NAME,
   147  		"--cloud-providers", "gce,kubernetes",
   148  		"--gate-endpoint", ts.URL,
   149  	}
   150  	rootCmd.SetArgs(args)
   151  	err := rootCmd.Execute()
   152  	if err == nil {
   153  		t.Fatalf("Command failed with: %s", err)
   154  	}
   155  
   156  	expected := ""
   157  	recieved := strings.TrimSpace(saveBuffer.String())
   158  	if expected != recieved {
   159  		t.Fatalf("Unexpected save request body:\n%s", recieved)
   160  	}
   161  }
   162  
   163  func TestApplicationSave_missingproviders(t *testing.T) {
   164  	saveBuffer := new(bytes.Buffer)
   165  	ts := testGateAppSaveSuccess(saveBuffer)
   166  	defer ts.Close()
   167  
   168  	rootCmd, options := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard)
   169  	rootCmd.AddCommand(NewApplicationCmd(options))
   170  
   171  	args := []string{
   172  		"application", "save",
   173  		"--application-name", NAME,
   174  		"--owner-email", EMAIL,
   175  		"--gate-endpoint", ts.URL,
   176  	}
   177  	rootCmd.SetArgs(args)
   178  	err := rootCmd.Execute()
   179  	if err == nil {
   180  		t.Fatalf("Command failed with: %s", err)
   181  	}
   182  
   183  	expected := ""
   184  	recieved := strings.TrimSpace(saveBuffer.String())
   185  	if expected != recieved {
   186  		t.Fatalf("Unexpected save request body:\n%s", recieved)
   187  	}
   188  }
   189  
   190  func TestApplicationSave_filejson(t *testing.T) {
   191  	saveBuffer := new(bytes.Buffer)
   192  	ts := testGateAppSaveSuccess(saveBuffer)
   193  	defer ts.Close()
   194  
   195  	tempFile := tempAppFile(testAppJsonStr)
   196  	if tempFile == nil {
   197  		t.Fatal("Could not create temp app file.")
   198  	}
   199  	defer os.Remove(tempFile.Name())
   200  
   201  	rootCmd, options := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard)
   202  	rootCmd.AddCommand(NewApplicationCmd(options))
   203  
   204  	args := []string{
   205  		"application", "save",
   206  		"--file", tempFile.Name(),
   207  		"--gate-endpoint", ts.URL,
   208  	}
   209  	rootCmd.SetArgs(args)
   210  	err := rootCmd.Execute()
   211  	if err != nil {
   212  		t.Fatalf("Command failed with: %s", err)
   213  	}
   214  
   215  	expected := strings.TrimSpace(testAppTaskJsonStr)
   216  	recieved := saveBuffer.Bytes()
   217  	util.TestPrettyJsonDiff(t, "save request body", expected, recieved)
   218  }
   219  
   220  func TestApplicationSave_fileyaml(t *testing.T) {
   221  	saveBuffer := new(bytes.Buffer)
   222  	ts := testGateAppSaveSuccess(saveBuffer)
   223  	defer ts.Close()
   224  
   225  	tempFile := tempAppFile(testAppYamlStr)
   226  	if tempFile == nil {
   227  		t.Fatal("Could not create temp app file.")
   228  	}
   229  	defer os.Remove(tempFile.Name())
   230  
   231  	rootCmd, options := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard)
   232  	rootCmd.AddCommand(NewApplicationCmd(options))
   233  
   234  	args := []string{
   235  		"application", "save",
   236  		"--file", tempFile.Name(),
   237  		"--gate-endpoint", ts.URL,
   238  	}
   239  	rootCmd.SetArgs(args)
   240  	err := rootCmd.Execute()
   241  	if err != nil {
   242  		t.Fatalf("Command failed with: %s", err)
   243  	}
   244  
   245  	expected := strings.TrimSpace(testAppTaskJsonStr)
   246  	recieved := saveBuffer.Bytes()
   247  	util.TestPrettyJsonDiff(t, "save request body", expected, recieved)
   248  }
   249  
   250  func TestApplicationSave_stdinjson(t *testing.T) {
   251  	saveBuffer := new(bytes.Buffer)
   252  	ts := testGateAppSaveSuccess(saveBuffer)
   253  	defer ts.Close()
   254  
   255  	tempFile := tempAppFile(testAppJsonStr)
   256  	if tempFile == nil {
   257  		t.Fatal("Could not create temp app file.")
   258  	}
   259  	defer os.Remove(tempFile.Name())
   260  
   261  	// Prepare Stdin for test reading.
   262  	tempFile.Seek(0, 0)
   263  	oldStdin := os.Stdin
   264  	defer func() { os.Stdin = oldStdin }()
   265  	os.Stdin = tempFile
   266  
   267  	rootCmd, options := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard)
   268  	rootCmd.AddCommand(NewApplicationCmd(options))
   269  
   270  	args := []string{
   271  		"application", "save",
   272  		"--gate-endpoint", ts.URL,
   273  	}
   274  	rootCmd.SetArgs(args)
   275  	err := rootCmd.Execute()
   276  	if err != nil {
   277  		t.Fatalf("Command failed with: %s", err)
   278  	}
   279  
   280  	expected := strings.TrimSpace(testAppTaskJsonStr)
   281  	recieved := saveBuffer.Bytes()
   282  	util.TestPrettyJsonDiff(t, "save request body", expected, recieved)
   283  }
   284  
   285  func TestApplicationSave_stdinyaml(t *testing.T) {
   286  	saveBuffer := new(bytes.Buffer)
   287  	ts := testGateAppSaveSuccess(saveBuffer)
   288  	defer ts.Close()
   289  
   290  	tempFile := tempAppFile(testAppYamlStr)
   291  	if tempFile == nil {
   292  		t.Fatal("Could not create temp app file.")
   293  	}
   294  	defer os.Remove(tempFile.Name())
   295  
   296  	// Prepare Stdin for test reading.
   297  	tempFile.Seek(0, 0)
   298  	oldStdin := os.Stdin
   299  	defer func() { os.Stdin = oldStdin }()
   300  	os.Stdin = tempFile
   301  
   302  	rootCmd, options := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard)
   303  	rootCmd.AddCommand(NewApplicationCmd(options))
   304  
   305  	args := []string{
   306  		"application", "save",
   307  		"--gate-endpoint", ts.URL,
   308  	}
   309  	rootCmd.SetArgs(args)
   310  	err := rootCmd.Execute()
   311  	if err != nil {
   312  		t.Fatalf("Command failed with: %s", err)
   313  	}
   314  
   315  	expected := strings.TrimSpace(testAppTaskJsonStr)
   316  	recieved := saveBuffer.Bytes()
   317  	util.TestPrettyJsonDiff(t, "save request body", expected, recieved)
   318  }
   319  
   320  // testGateFail spins up a local http server that we will configure the GateClient
   321  // to direct requests to. Responds with a 500 InternalServerError.
   322  func testGateFail() *httptest.Server {
   323  	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   324  		// TODO(jacobkiefer): Mock more robust errors once implemented upstream.
   325  		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
   326  	}))
   327  }
   328  
   329  // testGateAppSaveSuccess spins up a local http server that we will configure the GateClient
   330  // to direct requests to. Responds with successful responses to pipeline execute API calls.
   331  // Writes request body to buffer for testing.
   332  func testGateAppSaveSuccess(buffer io.Writer) *httptest.Server {
   333  	mux := util.TestGateMuxWithVersionHandler()
   334  	mux.Handle(
   335  		"/tasks",
   336  		util.NewTestBufferHandlerFunc(http.MethodPost, buffer, http.StatusOK, strings.TrimSpace(testAppTaskRefJsonStr)),
   337  	)
   338  	mux.Handle("/tasks/id", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   339  		w.Header().Add("content-type", "application/json")
   340  		fmt.Fprintln(w, strings.TrimSpace(testAppTaskStatusJsonStr))
   341  	}))
   342  	return httptest.NewServer(mux)
   343  }
   344  
   345  func tempAppFile(appContent string) *os.File {
   346  	tempFile, _ := ioutil.TempFile("" /* /tmp dir. */, "app-spec")
   347  	bytes, err := tempFile.Write([]byte(appContent))
   348  	if err != nil || bytes == 0 {
   349  		fmt.Println("Could not write temp file.")
   350  		return nil
   351  	}
   352  	return tempFile
   353  }
   354  
   355  const testAppTaskRefJsonStr = `
   356  {
   357   "ref": "/tasks/id"
   358  }
   359  `
   360  
   361  const testAppTaskStatusJsonStr = `
   362  {
   363   "status": "SUCCEEDED"
   364  }
   365  `
   366  
   367  const testAppJsonStr = `
   368  {
   369     "email" : "appowner@spinnaker-test.net",
   370     "cloudProviders" : "gce,kubernetes",
   371     "name" : "app",
   372  	 "instancePort": 80
   373  }
   374  `
   375  
   376  const testAppYamlStr = `
   377  email: appowner@spinnaker-test.net
   378  cloudProviders: gce,kubernetes
   379  name: app
   380  instancePort: 80
   381  `
   382  
   383  const testAppTaskJsonStr = `
   384  {
   385   "application": "app",
   386   "description": "Create Application: app",
   387   "job": [
   388    {
   389     "application": {
   390      "cloudProviders": "gce,kubernetes",
   391      "email": "appowner@spinnaker-test.net",
   392      "instancePort": 80,
   393      "name": "app"
   394     },
   395     "type": "createApplication"
   396    }
   397   ]
   398  }
   399  `