github.com/asifdxtreme/cli@v6.1.3-0.20150123051144-9ead8700b4ae+incompatible/cf/commands/application/logs_test.go (about) 1 package application_test 2 3 import ( 4 "time" 5 6 "code.google.com/p/gogoprotobuf/proto" 7 testapi "github.com/cloudfoundry/cli/cf/api/fakes" 8 "github.com/cloudfoundry/cli/cf/errors" 9 "github.com/cloudfoundry/cli/cf/models" 10 "github.com/cloudfoundry/cli/cf/terminal" 11 testcmd "github.com/cloudfoundry/cli/testhelpers/commands" 12 testconfig "github.com/cloudfoundry/cli/testhelpers/configuration" 13 testlogs "github.com/cloudfoundry/cli/testhelpers/logs" 14 testreq "github.com/cloudfoundry/cli/testhelpers/requirements" 15 testterm "github.com/cloudfoundry/cli/testhelpers/terminal" 16 "github.com/cloudfoundry/loggregatorlib/logmessage" 17 18 . "github.com/cloudfoundry/cli/cf/commands/application" 19 "github.com/cloudfoundry/cli/cf/configuration/core_config" 20 . "github.com/cloudfoundry/cli/testhelpers/matchers" 21 . "github.com/onsi/ginkgo" 22 . "github.com/onsi/gomega" 23 ) 24 25 var _ = Describe("logs command", func() { 26 var ( 27 ui *testterm.FakeUI 28 logsRepo *testapi.FakeLogsRepository 29 requirementsFactory *testreq.FakeReqFactory 30 configRepo core_config.ReadWriter 31 ) 32 33 BeforeEach(func() { 34 ui = &testterm.FakeUI{} 35 configRepo = testconfig.NewRepositoryWithDefaults() 36 logsRepo = &testapi.FakeLogsRepository{} 37 requirementsFactory = &testreq.FakeReqFactory{} 38 }) 39 40 runCommand := func(args ...string) bool { 41 return testcmd.RunCommand(NewLogs(ui, configRepo, logsRepo), args, requirementsFactory) 42 } 43 44 Describe("requirements", func() { 45 It("fails with usage when called without one argument", func() { 46 requirementsFactory.LoginSuccess = true 47 48 runCommand() 49 Expect(ui.FailedWithUsage).To(BeTrue()) 50 }) 51 52 It("fails requirements when not logged in", func() { 53 Expect(runCommand("my-app")).To(BeFalse()) 54 }) 55 }) 56 57 Context("when logged in", func() { 58 var ( 59 app models.Application 60 ) 61 62 BeforeEach(func() { 63 requirementsFactory.LoginSuccess = true 64 65 app = models.Application{} 66 app.Name = "my-app" 67 app.Guid = "my-app-guid" 68 69 currentTime := time.Now() 70 recentLogs := []*logmessage.LogMessage{ 71 testlogs.NewLogMessage("Log Line 1", app.Guid, "DEA", currentTime), 72 testlogs.NewLogMessage("Log Line 2", app.Guid, "DEA", currentTime), 73 } 74 75 appLogs := []*logmessage.LogMessage{ 76 testlogs.NewLogMessage("Log Line 1", app.Guid, "DEA", time.Now()), 77 } 78 79 requirementsFactory.Application = app 80 logsRepo.RecentLogsForReturns(recentLogs, nil) 81 82 logsRepo.TailLogsForStub = func(appGuid string, onConnect func(), onMessage func(*logmessage.LogMessage)) error { 83 onConnect() 84 for _, log := range appLogs { 85 onMessage(log) 86 } 87 return nil 88 } 89 }) 90 91 It("shows the recent logs when the --recent flag is provided", func() { 92 runCommand("--recent", "my-app") 93 94 Expect(requirementsFactory.ApplicationName).To(Equal("my-app")) 95 Expect(app.Guid).To(Equal(logsRepo.RecentLogsForArgsForCall(0))) 96 Expect(ui.Outputs).To(ContainSubstrings( 97 []string{"Connected, dumping recent logs for app", "my-app", "my-org", "my-space", "my-user"}, 98 []string{"Log Line 1"}, 99 []string{"Log Line 2"}, 100 )) 101 }) 102 103 Context("when the log messages contain format string identifiers", func() { 104 BeforeEach(func() { 105 logsRepo.RecentLogsForReturns([]*logmessage.LogMessage{ 106 testlogs.NewLogMessage("hello%2Bworld%v", app.Guid, "DEA", time.Now()), 107 }, nil) 108 }) 109 110 It("does not treat them as format strings", func() { 111 runCommand("--recent", "my-app") 112 Expect(ui.Outputs).To(ContainSubstrings([]string{"hello%2Bworld%v"})) 113 }) 114 }) 115 116 It("tails the app's logs when no flags are given", func() { 117 runCommand("my-app") 118 119 Expect(requirementsFactory.ApplicationName).To(Equal("my-app")) 120 appGuid, _, _ := logsRepo.TailLogsForArgsForCall(0) 121 Expect(app.Guid).To(Equal(appGuid)) 122 Expect(ui.Outputs).To(ContainSubstrings( 123 []string{"Connected, tailing logs for app", "my-app", "my-org", "my-space", "my-user"}, 124 []string{"Log Line 1"}, 125 )) 126 }) 127 128 Context("when the loggregator server has an invalid cert", func() { 129 Context("when the skip-ssl-validation flag is not set", func() { 130 It("fails and informs the user about the skip-ssl-validation flag", func() { 131 logsRepo.TailLogsForReturns(errors.NewInvalidSSLCert("https://example.com", "it don't work good")) 132 runCommand("my-app") 133 134 Expect(ui.Outputs).To(ContainSubstrings( 135 []string{"Received invalid SSL certificate", "https://example.com"}, 136 []string{"TIP"}, 137 )) 138 }) 139 140 It("informs the user of the error when they include the --recent flag", func() { 141 logsRepo.RecentLogsForReturns(nil, errors.NewInvalidSSLCert("https://example.com", "how does SSL work???")) 142 runCommand("--recent", "my-app") 143 144 Expect(ui.Outputs).To(ContainSubstrings( 145 []string{"Received invalid SSL certificate", "https://example.com"}, 146 []string{"TIP"}, 147 )) 148 }) 149 }) 150 }) 151 152 Context("when the loggregator server has a valid cert", func() { 153 It("tails logs", func() { 154 runCommand("my-app") 155 Expect(ui.Outputs).To(ContainSubstrings( 156 []string{"Connected, tailing logs for app", "my-org", "my-space", "my-user"}, 157 )) 158 }) 159 }) 160 161 Describe("Helpers", func() { 162 date := time.Date(2014, 4, 4, 11, 39, 20, 5, time.UTC) 163 164 createMessage := func(sourceId string, sourceName string, msgType logmessage.LogMessage_MessageType, date time.Time) *logmessage.LogMessage { 165 timestamp := date.UnixNano() 166 return &logmessage.LogMessage{ 167 Message: []byte("Hello World!\n\r\n\r"), 168 AppId: proto.String("my-app-guid"), 169 MessageType: &msgType, 170 SourceId: &sourceId, 171 Timestamp: ×tamp, 172 SourceName: &sourceName, 173 } 174 } 175 176 Context("when the message comes", func() { 177 It("include the instance index", func() { 178 msg := createMessage("4", "DEA", logmessage.LogMessage_OUT, date) 179 Expect(terminal.Decolorize(LogMessageOutput(msg, time.UTC))).To(Equal("2014-04-04T11:39:20.00+0000 [DEA/4] OUT Hello World!")) 180 }) 181 182 It("doesn't include the instance index if sourceID is empty", func() { 183 msg := createMessage("", "DEA", logmessage.LogMessage_OUT, date) 184 Expect(terminal.Decolorize(LogMessageOutput(msg, time.UTC))).To(Equal("2014-04-04T11:39:20.00+0000 [DEA] OUT Hello World!")) 185 }) 186 }) 187 188 Context("when the message was written to stderr", func() { 189 It("shows the log type as 'ERR'", func() { 190 msg := createMessage("4", "STG", logmessage.LogMessage_ERR, date) 191 Expect(terminal.Decolorize(LogMessageOutput(msg, time.UTC))).To(Equal("2014-04-04T11:39:20.00+0000 [STG/4] ERR Hello World!")) 192 }) 193 }) 194 195 It("formats the time in the given time zone", func() { 196 msg := createMessage("4", "RTR", logmessage.LogMessage_ERR, date) 197 Expect(terminal.Decolorize(LogMessageOutput(msg, time.FixedZone("the-zone", 3*60*60)))).To(Equal("2014-04-04T14:39:20.00+0300 [RTR/4] ERR Hello World!")) 198 }) 199 }) 200 }) 201 })