github.com/jcarley/cli@v0.0.0-20180201210820-966d90434c30/commands/logs/logs_test.go (about)

     1  package logs
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net/http"
     7  	"strings"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/Sirupsen/logrus"
    12  	"github.com/daticahealth/cli/commands/environments"
    13  	"github.com/daticahealth/cli/commands/services"
    14  	"github.com/daticahealth/cli/commands/sites"
    15  	"github.com/daticahealth/cli/config"
    16  	"github.com/daticahealth/cli/lib/jobs"
    17  	"github.com/daticahealth/cli/models"
    18  	"github.com/daticahealth/cli/test"
    19  )
    20  
    21  type SLogsMock struct {
    22  	Settings *models.Settings
    23  }
    24  
    25  func (l *SLogsMock) RetrieveElasticsearchVersion(domain string) (string, error) {
    26  	return "5", nil
    27  }
    28  
    29  func (l *SLogsMock) Output(queryString, domain string, generator queryGenerator, from int, startTimestamp, endTimestamp time.Time, hostNames []string, fileName string) (int, error) {
    30  	appLogsIdentifier := "source"
    31  	appLogsValue := "app"
    32  	if strings.HasPrefix(domain, "csb01") {
    33  		appLogsIdentifier = "syslog_program"
    34  		appLogsValue = "supervisord"
    35  	}
    36  
    37  	logrus.Println("        @timestamp       -        message")
    38  	for {
    39  		queryBytes, err := generator(queryString, appLogsIdentifier, appLogsValue, startTimestamp, from, hostNames, fileName)
    40  		if err != nil {
    41  			return -1, fmt.Errorf("Error generating query: %s", err)
    42  		} else if queryBytes == nil || len(queryBytes) == 0 {
    43  			return -1, errors.New("Error generating query")
    44  		}
    45  
    46  		var logs models.Logs
    47  		var hits models.Hits
    48  		logHits := []models.LogHits{}
    49  		for i := 0; i < 3; i++ {
    50  			var logHit models.LogHits
    51  			logHit.ID = fmt.Sprintf("log_%d", i)
    52  			logHit.Score = 2.3
    53  			logHit.Index = "1"
    54  			logHit.Type = "THeHittenistLogHit"
    55  			logHit.Fields = make(map[string][]string)
    56  			logHit.Fields["@timestamp"] = []string{fmt.Sprintf("2017-10-11T15:04:0%d.999999999Z07:00", i)}
    57  			logHit.Fields["message"] = []string{fmt.Sprintf("Wow so log %d", i)}
    58  			logHits = append(logHits, logHit)
    59  		}
    60  		hits.Hits = &logHits
    61  		hits.MaxScore = 2.3
    62  		hits.Total = 1
    63  		logs.Hits = &hits
    64  
    65  		end := time.Time{}
    66  		for _, lh := range *logs.Hits.Hits {
    67  			logrus.Printf("%s - %s", lh.Fields["@timestamp"][0], lh.Fields["message"][0])
    68  			end, _ = time.Parse(time.RFC3339Nano, lh.Fields["@timestamp"][0])
    69  		}
    70  		amount := len(*logs.Hits.Hits)
    71  
    72  		from += len(*logs.Hits.Hits)
    73  		// TODO this will infinite loop if it always retrieves `size` hits
    74  		// and it fails to parse the end timestamp. very small window of opportunity.
    75  		if amount < size || end.After(endTimestamp) {
    76  			break
    77  		}
    78  		time.Sleep(config.JobPollTime * time.Second)
    79  	}
    80  	return from, nil
    81  }
    82  
    83  func (l *SLogsMock) Stream(queryString, domain string, generator queryGenerator, from int, timestamp time.Time, hostNames []string, fileName string) error {
    84  	//Don't want to run stream forever in test
    85  	for i := 0; i < 2; i++ {
    86  		f, err := l.Output(queryString, domain, generator, from, timestamp, time.Now(), hostNames, fileName)
    87  		if err != nil {
    88  			return err
    89  		}
    90  		from = f
    91  		time.Sleep(config.LogPollTime * time.Second)
    92  	}
    93  	return nil
    94  }
    95  
    96  func (l *SLogsMock) Watch(queryString, domain string) error {
    97  	//TODO: Mock it better?
    98  	return errors.New("Run Stream")
    99  }
   100  
   101  func muxSetup(mux *http.ServeMux, t *testing.T, serviceType string, createdAt []string, query *CMDLogQuery) {
   102  	mux.HandleFunc("/environments/"+test.EnvID+"/services/",
   103  		// Retrieve services
   104  		func(w http.ResponseWriter, r *http.Request) {
   105  			test.AssertEquals(t, r.Method, "GET")
   106  			fmt.Fprint(w, fmt.Sprintf(`[{"id":"%s","label":"%s","name":"%s","type":"%s","redeployable":false},{"id":"%s","label":"service_proxy","name":"service proxy","redeployable":true}]`, test.SvcID, test.SvcLabel, serviceType, serviceType, test.SvcIDAlt))
   107  		},
   108  	)
   109  	mux.HandleFunc("/environments/"+test.EnvID+"/services/"+test.SvcID+"/jobs/"+query.JobID,
   110  		//Retrieve job
   111  		func(w http.ResponseWriter, r *http.Request) {
   112  			test.AssertEquals(t, r.Method, "GET")
   113  			if query.JobID == test.JobID {
   114  				jobJSON := fmt.Sprintf(`{"id":"%s","type":"%s","target":"%s","status":"happy", "created_at":"%s"}`, test.JobID, "deploy", test.Target, createdAt[0])
   115  				fmt.Fprint(w, jobJSON)
   116  			} else {
   117  				fmt.Fprint(w, "")
   118  			}
   119  		},
   120  	)
   121  	mux.HandleFunc("/environments/"+test.EnvID+"/services/"+test.SvcID+"/jobs",
   122  		// RetrieveByTarget/Type
   123  		func(w http.ResponseWriter, r *http.Request) {
   124  			test.AssertEquals(t, r.Method, "GET")
   125  			var jobs []string
   126  			for i, created := range createdAt {
   127  				jobID := test.JobID
   128  				if i > 0 {
   129  					jobID = test.JobIDAlt
   130  				}
   131  				jobs = append(jobs, fmt.Sprintf(`{"id":"%s","type":"%s","target":"%s","status":"happy","created_at":"%s"}`, jobID, "worker", test.Target, created))
   132  			}
   133  			jobsJSON := fmt.Sprintf("[%s]", strings.Join(jobs, ","))
   134  			fmt.Fprint(w, jobsJSON)
   135  		},
   136  	)
   137  	mux.HandleFunc("/environments",
   138  		// Retrieve environment list
   139  		func(w http.ResponseWriter, r *http.Request) {
   140  			test.AssertEquals(t, r.Method, "GET")
   141  			if r.Header.Get("X-Pod-ID") == test.Pod {
   142  				fmt.Fprint(w, fmt.Sprintf(`[{"id":"%s","name":"%s","namespace":"%s","organizationId":"%s"}]`, test.EnvID, test.EnvName, test.Namespace, test.OrgID))
   143  			} else {
   144  				fmt.Fprint(w, fmt.Sprintf(`[{"id":"%s","name":"%s","namespace":"%s","organizationId":"%s"}]`, test.EnvIDAlt, test.EnvNameAlt, test.NamespaceAlt, test.OrgIDAlt))
   145  			}
   146  		},
   147  	)
   148  	mux.HandleFunc("/environments/"+test.EnvID,
   149  		// Retrieve environment by ID
   150  		func(w http.ResponseWriter, r *http.Request) {
   151  			test.AssertEquals(t, r.Method, "GET")
   152  			fmt.Fprint(w, fmt.Sprintf(`{"id":"%s","name":"%s","namespace":"%s","organizationId":"%s"}`, test.EnvID, test.EnvName, test.Namespace, test.OrgID))
   153  		},
   154  	)
   155  	mux.HandleFunc("/environments/"+test.EnvID+"/services/"+test.SvcIDAlt+"/sites",
   156  		// Retrieve site by ID
   157  		func(w http.ResponseWriter, r *http.Request) {
   158  			test.AssertEquals(t, r.Method, "GET")
   159  			fmt.Fprint(w, fmt.Sprintf(`[{"id":%d, "name":"%s"}]`, 123, test.Namespace+".supersite"))
   160  		},
   161  	)
   162  }
   163  
   164  func TestLogsService(t *testing.T) {
   165  	mux, server, baseURL := test.Setup()
   166  	defer test.Teardown(server)
   167  	settings := test.GetSettings(baseURL.String())
   168  	cmdQuery := CMDLogQuery{
   169  		Query:   "",
   170  		Follow:  false,
   171  		Service: test.SvcLabel,
   172  	}
   173  	muxSetup(mux, t, "code", []string{test.GoodDate}, &cmdQuery)
   174  
   175  	ilogs := &SLogsMock{
   176  		Settings: settings,
   177  	}
   178  	err := CmdLogs(&cmdQuery, settings.EnvironmentID, settings, ilogs, &test.FakePrompts{}, environments.New(settings), services.New(settings), jobs.New(settings), sites.New(settings))
   179  	if err != nil {
   180  		t.Fatalf("Unexpected error: %s", err)
   181  	}
   182  }
   183  
   184  func TestLogsJobID(t *testing.T) {
   185  	mux, server, baseURL := test.Setup()
   186  	defer test.Teardown(server)
   187  	settings := test.GetSettings(baseURL.String())
   188  	cmdQuery := CMDLogQuery{
   189  		Query:   "",
   190  		Follow:  false,
   191  		Service: test.SvcLabel,
   192  		JobID:   test.JobID,
   193  	}
   194  	muxSetup(mux, t, "code", []string{test.GoodDate}, &cmdQuery)
   195  
   196  	ilogs := &SLogsMock{
   197  		Settings: settings,
   198  	}
   199  	err := CmdLogs(&cmdQuery, settings.EnvironmentID, settings, ilogs, &test.FakePrompts{}, environments.New(settings), services.New(settings), jobs.New(settings), sites.New(settings))
   200  	if err != nil {
   201  		t.Fatalf("Unexpected error: %s", err)
   202  	}
   203  }
   204  
   205  func TestLogsTarget(t *testing.T) {
   206  	mux, server, baseURL := test.Setup()
   207  	defer test.Teardown(server)
   208  	settings := test.GetSettings(baseURL.String())
   209  	cmdQuery := CMDLogQuery{
   210  		Query:   "",
   211  		Follow:  false,
   212  		Service: test.SvcLabel,
   213  		Target:  test.Target,
   214  	}
   215  	muxSetup(mux, t, "code", []string{test.GoodDate, test.GoodDate}, &cmdQuery)
   216  
   217  	ilogs := &SLogsMock{
   218  		Settings: settings,
   219  	}
   220  	err := CmdLogs(&cmdQuery, settings.EnvironmentID, settings, ilogs, &test.FakePrompts{}, environments.New(settings), services.New(settings), jobs.New(settings), sites.New(settings))
   221  	if err != nil {
   222  		t.Fatalf("Unexpected error: %s", err)
   223  	}
   224  }
   225  
   226  func TestLogsStream(t *testing.T) {
   227  	mux, server, baseURL := test.Setup()
   228  	defer test.Teardown(server)
   229  	settings := test.GetSettings(baseURL.String())
   230  	cmdQuery := CMDLogQuery{
   231  		Query:   "",
   232  		Follow:  true,
   233  		Service: test.SvcLabel,
   234  	}
   235  	muxSetup(mux, t, "code", []string{test.GoodDate}, &cmdQuery)
   236  
   237  	ilogs := &SLogsMock{
   238  		Settings: settings,
   239  	}
   240  	err := CmdLogs(&cmdQuery, settings.EnvironmentID, settings, ilogs, &test.FakePrompts{}, environments.New(settings), services.New(settings), jobs.New(settings), sites.New(settings))
   241  	if err != nil {
   242  		t.Fatalf("Unexpected error: %s", err)
   243  	}
   244  }
   245  
   246  func TestLogsBadService(t *testing.T) {
   247  	mux, server, baseURL := test.Setup()
   248  	defer test.Teardown(server)
   249  	settings := test.GetSettings(baseURL.String())
   250  	cmdQuery := CMDLogQuery{
   251  		Query:   "",
   252  		Follow:  false,
   253  		Service: "BadServiceLabel",
   254  	}
   255  	muxSetup(mux, t, "code", []string{test.BadDate}, &cmdQuery)
   256  
   257  	ilogs := &SLogsMock{
   258  		Settings: settings,
   259  	}
   260  	err := CmdLogs(&cmdQuery, settings.EnvironmentID, settings, ilogs, &test.FakePrompts{}, environments.New(settings), services.New(settings), jobs.New(settings), sites.New(settings))
   261  	expectedErr := fmt.Sprintf("Cannot find the specified service \"%s\".", cmdQuery.Service)
   262  	if err == nil {
   263  		t.Fatalf("Expected: %s\n", expectedErr)
   264  	} else if err.Error() != expectedErr {
   265  		t.Fatalf("Expected: %s\nGot: %s", expectedErr, err)
   266  	}
   267  }
   268  
   269  func TestLogsBadRequestMissingService(t *testing.T) {
   270  	mux, server, baseURL := test.Setup()
   271  	defer test.Teardown(server)
   272  	settings := test.GetSettings(baseURL.String())
   273  	cmdQuery := CMDLogQuery{
   274  		Query:  "",
   275  		Follow: false,
   276  		Target: test.Target,
   277  	}
   278  	muxSetup(mux, t, "code", []string{test.GoodDate}, &cmdQuery)
   279  
   280  	ilogs := &SLogsMock{
   281  		Settings: settings,
   282  	}
   283  	err := CmdLogs(&cmdQuery, settings.EnvironmentID, settings, ilogs, &test.FakePrompts{}, environments.New(settings), services.New(settings), jobs.New(settings), sites.New(settings))
   284  	expectedErr := "You must specify a code service to query the logs for a particular target"
   285  	if err == nil {
   286  		t.Fatalf("Expected: %s\n", expectedErr)
   287  	} else if err.Error() != expectedErr {
   288  		t.Fatalf("Expected: %s\nGot: %s", expectedErr, err)
   289  	}
   290  }
   291  
   292  func TestLogsBadRequestTargetAndJobID(t *testing.T) {
   293  	mux, server, baseURL := test.Setup()
   294  	defer test.Teardown(server)
   295  	settings := test.GetSettings(baseURL.String())
   296  	cmdQuery := CMDLogQuery{
   297  		Query:  "",
   298  		Follow: false,
   299  		Target: test.Target,
   300  		JobID:  test.JobID,
   301  	}
   302  	muxSetup(mux, t, "code", []string{test.GoodDate}, &cmdQuery)
   303  
   304  	ilogs := &SLogsMock{
   305  		Settings: settings,
   306  	}
   307  	err := CmdLogs(&cmdQuery, settings.EnvironmentID, settings, ilogs, &test.FakePrompts{}, environments.New(settings), services.New(settings), jobs.New(settings), sites.New(settings))
   308  	expectedErr := "Specifying \"--job-id\" in combination with \"--target\" is unsupported."
   309  	if err == nil {
   310  		t.Fatalf("Expected: %s\n", expectedErr)
   311  	} else if err.Error() != expectedErr {
   312  		t.Fatalf("Expected: %s\nGot: %s", expectedErr, err)
   313  	}
   314  }
   315  
   316  func TestLogsBadRequestTargetNonCodeService(t *testing.T) {
   317  	mux, server, baseURL := test.Setup()
   318  	defer test.Teardown(server)
   319  	settings := test.GetSettings(baseURL.String())
   320  	cmdQuery := CMDLogQuery{
   321  		Query:   "",
   322  		Follow:  false,
   323  		Service: test.SvcLabel,
   324  		Target:  test.Target,
   325  	}
   326  	muxSetup(mux, t, "database", []string{test.GoodDate}, &cmdQuery)
   327  
   328  	ilogs := &SLogsMock{
   329  		Settings: settings,
   330  	}
   331  	err := CmdLogs(&cmdQuery, settings.EnvironmentID, settings, ilogs, &test.FakePrompts{}, environments.New(settings), services.New(settings), jobs.New(settings), sites.New(settings))
   332  	expectedErr := "Cannot specifiy a target for a non-code service type"
   333  	if err == nil {
   334  		t.Fatalf("Expected: %s\n", expectedErr)
   335  	} else if err.Error() != expectedErr {
   336  		t.Fatalf("Expected: %s\nGot: %s", expectedErr, err)
   337  	}
   338  }
   339  
   340  func TestLogsBadServiceWithTarget(t *testing.T) {
   341  	mux, server, baseURL := test.Setup()
   342  	defer test.Teardown(server)
   343  	settings := test.GetSettings(baseURL.String())
   344  	cmdQuery := CMDLogQuery{
   345  		Query:   "",
   346  		Follow:  false,
   347  		Service: "BadServiceLabel",
   348  		Target:  test.Target,
   349  	}
   350  	muxSetup(mux, t, "code", []string{test.GoodDate}, &cmdQuery)
   351  
   352  	ilogs := &SLogsMock{
   353  		Settings: settings,
   354  	}
   355  	err := CmdLogs(&cmdQuery, settings.EnvironmentID, settings, ilogs, &test.FakePrompts{}, environments.New(settings), services.New(settings), jobs.New(settings), sites.New(settings))
   356  	expectedErr := fmt.Sprintf("Cannot find the specified service \"%s\".", cmdQuery.Service)
   357  	if err == nil {
   358  		t.Fatalf("Expected: %s\n", expectedErr)
   359  	} else if err.Error() != expectedErr {
   360  		t.Fatalf("Expected: %s\nGot: %s", expectedErr, err)
   361  	}
   362  }
   363  
   364  func TestLogsBadJobID(t *testing.T) {
   365  	mux, server, baseURL := test.Setup()
   366  	defer test.Teardown(server)
   367  	settings := test.GetSettings(baseURL.String())
   368  	cmdQuery := CMDLogQuery{
   369  		Query:   "",
   370  		Follow:  false,
   371  		Service: test.SvcLabel,
   372  		JobID:   "BadJobID",
   373  	}
   374  	muxSetup(mux, t, "code", []string{test.GoodDate}, &cmdQuery)
   375  
   376  	ilogs := &SLogsMock{
   377  		Settings: settings,
   378  	}
   379  	err := CmdLogs(&cmdQuery, settings.EnvironmentID, settings, ilogs, &test.FakePrompts{}, environments.New(settings), services.New(settings), jobs.New(settings), sites.New(settings))
   380  	expectedErr := fmt.Sprintf("Cannot find the specified job \"%s\".", cmdQuery.JobID)
   381  	if err == nil {
   382  		t.Fatalf("Expected: %s\n", expectedErr)
   383  	} else if err.Error() != expectedErr {
   384  		t.Fatalf("Expected: %s\nGot: %s", expectedErr, err)
   385  	}
   386  }
   387  
   388  func TestLogsBadTarget(t *testing.T) {
   389  	mux, server, baseURL := test.Setup()
   390  	defer test.Teardown(server)
   391  	settings := test.GetSettings(baseURL.String())
   392  	cmdQuery := CMDLogQuery{
   393  		Query:   "",
   394  		Follow:  false,
   395  		Service: test.SvcLabel,
   396  		Target:  "BadTarget",
   397  	}
   398  	muxSetup(mux, t, "code", []string{test.GoodDate}, &cmdQuery)
   399  
   400  	ilogs := &SLogsMock{
   401  		Settings: settings,
   402  	}
   403  	err := CmdLogs(&cmdQuery, settings.EnvironmentID, settings, ilogs, &test.FakePrompts{}, environments.New(settings), services.New(settings), jobs.New(settings), sites.New(settings))
   404  	expectedErr := fmt.Sprintf("Cannot find any jobs with target \"%s\" for service \"%s\"", cmdQuery.Target, test.SvcID)
   405  	if err == nil {
   406  		t.Fatalf("Expected: %s\n", expectedErr)
   407  	} else if err.Error() != expectedErr {
   408  		t.Fatalf("Expected: %s\nGot: %s", expectedErr, err)
   409  	}
   410  }
   411  
   412  func TestLogsNoValidHostNames(t *testing.T) {
   413  	mux, server, baseURL := test.Setup()
   414  	defer test.Teardown(server)
   415  	settings := test.GetSettings(baseURL.String())
   416  	cmdQuery := CMDLogQuery{
   417  		Query:   "",
   418  		Follow:  false,
   419  		Service: test.SvcLabel,
   420  		Target:  test.Target,
   421  	}
   422  	muxSetup(mux, t, "code", []string{test.BadDate, test.BadDate}, &cmdQuery)
   423  
   424  	ilogs := &SLogsMock{
   425  		Settings: settings,
   426  	}
   427  	err := CmdLogs(&cmdQuery, settings.EnvironmentID, settings, ilogs, &test.FakePrompts{}, environments.New(settings), services.New(settings), jobs.New(settings), sites.New(settings))
   428  	expectedErr := fmt.Sprintf(`All %d jobs for the service "%s"%s do not have valid hostnames to allow their logs to be queried. Redeploy the service if you would like to use this functionality.`, 2, cmdQuery.Service, fmt.Sprintf(` that have a target of "%s"`, cmdQuery.Target))
   429  	if err == nil || err.Error() != expectedErr {
   430  		t.Fatalf("Expected: %s\nGot: %s", expectedErr, err)
   431  	}
   432  }
   433  
   434  func TestLogsOneValidHostName(t *testing.T) {
   435  	mux, server, baseURL := test.Setup()
   436  	defer test.Teardown(server)
   437  	settings := test.GetSettings(baseURL.String())
   438  	cmdQuery := CMDLogQuery{
   439  		Query:   "",
   440  		Follow:  false,
   441  		Service: test.SvcLabel,
   442  		Target:  test.Target,
   443  	}
   444  	muxSetup(mux, t, "code", []string{test.BadDate, test.GoodDate, test.BadDate, test.BadDate}, &cmdQuery)
   445  
   446  	ilogs := &SLogsMock{
   447  		Settings: settings,
   448  	}
   449  
   450  	err := CmdLogs(&cmdQuery, settings.EnvironmentID, settings, ilogs, &test.FakePrompts{}, environments.New(settings), services.New(settings), jobs.New(settings), sites.New(settings))
   451  	if err != nil {
   452  		t.Fatalf("Unexpected error: %s", err)
   453  	}
   454  }