1package application_test 2 3import ( 4 "errors" 5 6 "github.com/cloudfoundry/bosh-bootloader/application" 7 "github.com/cloudfoundry/bosh-bootloader/commands" 8 "github.com/cloudfoundry/bosh-bootloader/fakes" 9 "github.com/cloudfoundry/bosh-bootloader/storage" 10 11 . "github.com/onsi/ginkgo" 12 . "github.com/onsi/ginkgo/extensions/table" 13 . "github.com/onsi/gomega" 14) 15 16var _ = Describe("App", func() { 17 var ( 18 app application.App 19 helpCmd *fakes.Command 20 versionCmd *fakes.Command 21 someCmd *fakes.Command 22 errorCmd *fakes.Command 23 usage *fakes.Usage 24 ) 25 26 var NewAppWithConfiguration = func(configuration application.Configuration) application.App { 27 return application.New(application.CommandSet{ 28 "help": helpCmd, 29 "version": versionCmd, 30 "--version": versionCmd, 31 "some": someCmd, 32 "error": errorCmd, 33 }, 34 configuration, 35 usage, 36 ) 37 } 38 39 BeforeEach(func() { 40 helpCmd = &fakes.Command{} 41 versionCmd = &fakes.Command{} 42 errorCmd = &fakes.Command{} 43 44 someCmd = &fakes.Command{} 45 someCmd.ExecuteCall.PassState = true 46 47 usage = &fakes.Usage{} 48 49 app = NewAppWithConfiguration(application.Configuration{}) 50 }) 51 52 Describe("Run", func() { 53 Context("executing commands", func() { 54 It("executes the command with flags", func() { 55 app = NewAppWithConfiguration(application.Configuration{ 56 Command: "some", 57 SubcommandFlags: []string{ 58 "--first-subcommand-flag", "first-value", 59 "--second-subcommand-flag", "second-value", 60 }, 61 Global: application.GlobalConfiguration{ 62 StateDir: "some/state/dir", 63 }, 64 State: storage.State{}, 65 }) 66 67 Expect(app.Run()).To(Succeed()) 68 69 Expect(someCmd.ExecuteCall.CallCount).To(Equal(1)) 70 Expect(someCmd.ExecuteCall.Receives.SubcommandFlags).To(Equal([]string{ 71 "--first-subcommand-flag", "first-value", 72 "--second-subcommand-flag", "second-value", 73 })) 74 }) 75 }) 76 77 Context("when name is passed as a global flag", func() { 78 DescribeTable("propagates name to subcommand flags", func(command string) { 79 commandFake := &fakes.Command{} 80 81 app = application.New( 82 application.CommandSet{ 83 command: commandFake, 84 }, 85 application.Configuration{ 86 Command: command, 87 SubcommandFlags: []string{ 88 "--first-subcommand-flag", "first-value", 89 "--second-subcommand-flag", "second-value", 90 }, 91 Global: application.GlobalConfiguration{ 92 StateDir: "some/state/dir", 93 Name: "some-env-name", 94 }, 95 State: storage.State{}, 96 }, 97 usage) 98 99 Expect(app.Run()).To(Succeed()) 100 101 Expect(commandFake.ExecuteCall.CallCount).To(Equal(1)) 102 Expect(commandFake.ExecuteCall.Receives.SubcommandFlags).To(Equal([]string{ 103 "--first-subcommand-flag", "first-value", 104 "--second-subcommand-flag", "second-value", 105 "--name", "some-env-name", 106 })) 107 }, 108 Entry("when command is plan", "plan"), 109 Entry("when command is up", "up"), 110 ) 111 }) 112 113 Context("when subcommand flags contains help", func() { 114 DescribeTable("prints command specific usage when help subcommand flag is provided", func(helpFlag string) { 115 someCmd.UsageCall.Returns.Usage = "some usage message" 116 117 app = NewAppWithConfiguration(application.Configuration{ 118 Command: "some", 119 SubcommandFlags: []string{helpFlag}, 120 ShowCommandHelp: true, 121 }) 122 123 Expect(app.Run()).To(Succeed()) 124 Expect(someCmd.UsageCall.CallCount).To(Equal(1)) 125 Expect(usage.PrintCommandUsageCall.CallCount).To(Equal(1)) 126 Expect(usage.PrintCommandUsageCall.Receives.Message).To(Equal("some usage message")) 127 Expect(usage.PrintCommandUsageCall.Receives.Command).To(Equal("some")) 128 Expect(someCmd.ExecuteCall.CallCount).To(Equal(0)) 129 }, 130 Entry("when --help is provided", "--help"), 131 Entry("when -h is provided", "-h"), 132 ) 133 }) 134 135 Context("when help is called with a command", func() { 136 It("prints the command specific help", func() { 137 someCmd.UsageCall.Returns.Usage = "some usage message" 138 139 app = NewAppWithConfiguration(application.Configuration{ 140 Command: "help", 141 SubcommandFlags: []string{"some"}, 142 }) 143 144 Expect(app.Run()).To(Succeed()) 145 Expect(someCmd.UsageCall.CallCount).To(Equal(1)) 146 Expect(usage.PrintCommandUsageCall.CallCount).To(Equal(1)) 147 Expect(usage.PrintCommandUsageCall.Receives.Message).To(Equal("some usage message")) 148 Expect(usage.PrintCommandUsageCall.Receives.Command).To(Equal("some")) 149 Expect(someCmd.ExecuteCall.CallCount).To(Equal(0)) 150 }) 151 152 Context("failure cases", func() { 153 Context("when a invalid subcommand is passed", func() { 154 BeforeEach(func() { 155 app = NewAppWithConfiguration(application.Configuration{ 156 Command: "help", 157 SubcommandFlags: []string{"invalid-command"}, 158 }) 159 }) 160 161 It("prints the usage", func() { 162 err := app.Run() 163 Expect(err).To(MatchError("unknown command: invalid-command")) 164 Expect(someCmd.ExecuteCall.CallCount).To(Equal(0)) 165 Expect(usage.PrintCall.CallCount).To(Equal(1)) 166 }) 167 }) 168 }) 169 }) 170 171 Context("when --version is the command", func() { 172 It("executes the command", func() { 173 app = NewAppWithConfiguration(application.Configuration{ 174 Command: "--version", 175 SubcommandFlags: []string{ 176 "--first-subcommand-flag", "first-value", 177 "--second-subcommand-flag", "second-value", 178 }, 179 }) 180 181 Expect(app.Run()).To(Succeed()) 182 183 Expect(versionCmd.ExecuteCall.CallCount).To(Equal(1)) 184 Expect(versionCmd.ExecuteCall.Receives.SubcommandFlags).To(Equal([]string{})) 185 }) 186 }) 187 188 Context("when subcommand flags contains version", func() { 189 DescribeTable("prints version when version subcommand flag is provided", func(versionFlag string) { 190 app = NewAppWithConfiguration(application.Configuration{ 191 Command: "some", 192 SubcommandFlags: []string{versionFlag}, 193 }) 194 195 Expect(app.Run()).To(Succeed()) 196 Expect(someCmd.ExecuteCall.CallCount).To(Equal(0)) 197 Expect(versionCmd.ExecuteCall.CallCount).To(Equal(1)) 198 Expect(versionCmd.ExecuteCall.Receives.SubcommandFlags).To(Equal([]string{})) 199 Expect(versionCmd.ExecuteCall.Receives.State).To(Equal(storage.State{})) 200 }, 201 Entry("when --version is provided", "--version"), 202 Entry("when -v is provided", "-v"), 203 ) 204 205 Context("error cases", func() { 206 Context("when version command is not part of the command set", func() { 207 BeforeEach(func() { 208 app = application.New(application.CommandSet{ 209 "some": someCmd, 210 }, application.Configuration{ 211 Command: "some", 212 SubcommandFlags: []string{"-v"}, 213 }, usage) 214 }) 215 216 It("returns an error", func() { 217 Expect(app.Run()).To(MatchError("unknown command: version")) 218 }) 219 }) 220 }) 221 }) 222 223 Context("error cases", func() { 224 Context("when a fast fail occurs", func() { 225 BeforeEach(func() { 226 someCmd.CheckFastFailsCall.Returns.Error = errors.New("fast failed command") 227 }) 228 229 It("returns an error and does not execute the command", func() { 230 app = NewAppWithConfiguration(application.Configuration{ 231 Command: "some", 232 }) 233 err := app.Run() 234 Expect(someCmd.CheckFastFailsCall.CallCount).To(Equal(1)) 235 Expect(err).To(MatchError("fast failed command")) 236 Expect(someCmd.ExecuteCall.CallCount).To(Equal(0)) 237 }) 238 }) 239 240 Context("when a fast fail occurs, but indicates that its a success", func() { 241 BeforeEach(func() { 242 someCmd.CheckFastFailsCall.Returns.Error = commands.ExitSuccessfully{} 243 }) 244 245 It("returns nil and doesn't execute the command", func() { 246 app = NewAppWithConfiguration(application.Configuration{ 247 Command: "some", 248 }) 249 err := app.Run() 250 Expect(someCmd.CheckFastFailsCall.CallCount).To(Equal(1)) 251 Expect(err).NotTo(HaveOccurred()) 252 Expect(someCmd.ExecuteCall.CallCount).To(Equal(0)) 253 }) 254 }) 255 256 Context("when an unknown command is provided", func() { 257 It("prints usage and returns an error", func() { 258 app = NewAppWithConfiguration(application.Configuration{ 259 Command: "some-unknown-command", 260 }) 261 err := app.Run() 262 Expect(err).To(MatchError("unknown command: some-unknown-command")) 263 Expect(usage.PrintCall.CallCount).To(Equal(1)) 264 }) 265 }) 266 267 Context("when the command fails to execute", func() { 268 It("returns an error", func() { 269 errorCmd.ExecuteCall.Returns.Error = errors.New("error executing command") 270 app = NewAppWithConfiguration(application.Configuration{ 271 Command: "error", 272 Global: application.GlobalConfiguration{ 273 Debug: true, 274 }, 275 }) 276 Expect(app.Run()).To(MatchError("error executing command")) 277 }) 278 }) 279 }) 280 }) 281}) 282