github.com/cloudfoundry-attic/ltc@v0.0.0-20151123212628-098adc7919fc/config/command_factory/config_command_factory_test.go (about)

     1  package command_factory_test
     2  
     3  import (
     4  	"errors"
     5  	"io"
     6  
     7  	. "github.com/onsi/ginkgo"
     8  	. "github.com/onsi/gomega"
     9  	"github.com/onsi/gomega/gbytes"
    10  
    11  	"github.com/cloudfoundry-incubator/ltc/config/command_factory"
    12  	"github.com/cloudfoundry-incubator/ltc/config/command_factory/fake_blob_store_verifier"
    13  	"github.com/cloudfoundry-incubator/ltc/config/persister"
    14  	"github.com/cloudfoundry-incubator/ltc/config/target_verifier/fake_target_verifier"
    15  	"github.com/cloudfoundry-incubator/ltc/exit_handler/exit_codes"
    16  	"github.com/cloudfoundry-incubator/ltc/exit_handler/fake_exit_handler"
    17  	"github.com/cloudfoundry-incubator/ltc/terminal"
    18  	"github.com/cloudfoundry-incubator/ltc/terminal/mocks"
    19  	"github.com/cloudfoundry-incubator/ltc/test_helpers"
    20  	"github.com/cloudfoundry-incubator/ltc/version/fake_version_manager"
    21  	"github.com/codegangsta/cli"
    22  
    23  	config_package "github.com/cloudfoundry-incubator/ltc/config"
    24  )
    25  
    26  var _ = Describe("CommandFactory", func() {
    27  	var (
    28  		stdinReader           *io.PipeReader
    29  		stdinWriter           *io.PipeWriter
    30  		outputBuffer          *gbytes.Buffer
    31  		terminalUI            terminal.UI
    32  		config                *config_package.Config
    33  		configPersister       persister.Persister
    34  		fakeTargetVerifier    *fake_target_verifier.FakeTargetVerifier
    35  		fakeBlobStoreVerifier *fake_blob_store_verifier.FakeBlobStoreVerifier
    36  		fakeExitHandler       *fake_exit_handler.FakeExitHandler
    37  		fakePasswordReader    *mocks.FakePasswordReader
    38  		fakeVersionManager    *fake_version_manager.FakeVersionManager
    39  	)
    40  
    41  	BeforeEach(func() {
    42  		stdinReader, stdinWriter = io.Pipe()
    43  		outputBuffer = gbytes.NewBuffer()
    44  		fakeExitHandler = &fake_exit_handler.FakeExitHandler{}
    45  		fakePasswordReader = &mocks.FakePasswordReader{}
    46  		terminalUI = terminal.NewUI(stdinReader, outputBuffer, fakePasswordReader)
    47  		fakeTargetVerifier = &fake_target_verifier.FakeTargetVerifier{}
    48  		fakeBlobStoreVerifier = &fake_blob_store_verifier.FakeBlobStoreVerifier{}
    49  		fakeVersionManager = &fake_version_manager.FakeVersionManager{}
    50  		configPersister = persister.NewMemPersister()
    51  		config = config_package.New(configPersister)
    52  	})
    53  
    54  	Describe("TargetCommand", func() {
    55  		var targetCommand cli.Command
    56  
    57  		verifyOldTargetStillSet := func() {
    58  			newConfig := config_package.New(configPersister)
    59  			Expect(newConfig.Load()).To(Succeed())
    60  
    61  			Expect(newConfig.Receptor()).To(Equal("http://olduser:oldpass@receptor.oldtarget.com"))
    62  		}
    63  
    64  		BeforeEach(func() {
    65  			commandFactory := command_factory.NewConfigCommandFactory(config, terminalUI, fakeTargetVerifier, fakeBlobStoreVerifier, fakeExitHandler, fakeVersionManager)
    66  			targetCommand = commandFactory.MakeTargetCommand()
    67  
    68  			config.SetTarget("oldtarget.com")
    69  			config.SetLogin("olduser", "oldpass")
    70  			Expect(config.Save()).To(Succeed())
    71  		})
    72  
    73  		Context("displaying the target", func() {
    74  			JustBeforeEach(func() {
    75  				test_helpers.ExecuteCommandWithArgs(targetCommand, []string{})
    76  			})
    77  
    78  			It("outputs the current user and target host", func() {
    79  				Expect(outputBuffer).To(test_helpers.SayLine("Target:\t\tolduser@oldtarget.com"))
    80  			})
    81  
    82  			Context("when no username is set", func() {
    83  				BeforeEach(func() {
    84  					config.SetLogin("", "")
    85  					Expect(config.Save()).To(Succeed())
    86  				})
    87  
    88  				It("only prints the target", func() {
    89  					Expect(outputBuffer).To(test_helpers.SayLine("Target:\t\toldtarget.com"))
    90  				})
    91  			})
    92  
    93  			Context("when no target is set", func() {
    94  				BeforeEach(func() {
    95  					config.SetTarget("")
    96  					Expect(config.Save()).To(Succeed())
    97  				})
    98  
    99  				It("informs the user the target is not set", func() {
   100  					Expect(outputBuffer).To(test_helpers.SayLine("Target not set."))
   101  				})
   102  			})
   103  
   104  			Context("when no blob store is targeted", func() {
   105  				It("should specify that no blob store is targeted", func() {
   106  					Expect(outputBuffer).To(test_helpers.SayLine("\tNo droplet store specified."))
   107  				})
   108  			})
   109  
   110  			Context("when a DAV blob store is targeted", func() {
   111  				BeforeEach(func() {
   112  					config.SetBlobStore("blobtarget.com", "8444", "blobUser", "password")
   113  					Expect(config.Save()).To(Succeed())
   114  				})
   115  
   116  				It("outputs the current user and blob store host", func() {
   117  					Expect(outputBuffer).To(test_helpers.SayLine("Droplet store:\tblobUser@blobtarget.com:8444"))
   118  				})
   119  
   120  				Context("when no blob store username is set", func() {
   121  					BeforeEach(func() {
   122  						config.SetBlobStore("blobtarget.com", "8444", "", "")
   123  						Expect(config.Save()).To(Succeed())
   124  					})
   125  
   126  					It("only prints the blob store host", func() {
   127  						Expect(outputBuffer).To(test_helpers.SayLine("Droplet store:\tblobtarget.com:8444"))
   128  					})
   129  				})
   130  			})
   131  
   132  			Context("when a S3 blob store is targeted", func() {
   133  				BeforeEach(func() {
   134  					config.SetS3BlobStore("access", "secret", "bucket", "region")
   135  					Expect(config.Save()).To(Succeed())
   136  				})
   137  
   138  				It("outputs the s3 bucket and region", func() {
   139  					Expect(outputBuffer).To(test_helpers.SayLine("Droplet store:\ts3://bucket (region)"))
   140  				})
   141  			})
   142  		})
   143  
   144  		Context("when --domain is pased", func() {
   145  			JustBeforeEach(func() {
   146  				test_helpers.ExecuteCommandWithArgs(targetCommand, []string{"--domain"})
   147  			})
   148  
   149  			It("outputs just the target host", func() {
   150  				Expect(string(outputBuffer.Contents())).To(Equal("oldtarget.com\n"))
   151  			})
   152  
   153  			Context("when no target is set", func() {
   154  				BeforeEach(func() {
   155  					config.SetTarget("")
   156  					Expect(config.Save()).To(Succeed())
   157  				})
   158  
   159  				It("informs the user the target is not set", func() {
   160  					Expect(string(outputBuffer.Contents())).To(BeEmpty())
   161  				})
   162  			})
   163  		})
   164  
   165  		Context("when initially connecting to the receptor without authentication", func() {
   166  			BeforeEach(func() {
   167  				fakeTargetVerifier.VerifyTargetReturns(true, true, nil)
   168  				fakeBlobStoreVerifier.VerifyReturns(true, nil)
   169  			})
   170  
   171  			It("saves the new receptor target", func() {
   172  				test_helpers.ExecuteCommandWithArgs(targetCommand, []string{"myapi.com"})
   173  
   174  				Expect(fakeTargetVerifier.VerifyTargetCallCount()).To(Equal(1))
   175  				Expect(fakeTargetVerifier.VerifyTargetArgsForCall(0)).To(Equal("http://receptor.myapi.com"))
   176  
   177  				newConfig := config_package.New(configPersister)
   178  				Expect(newConfig.Load()).To(Succeed())
   179  				Expect(newConfig.Receptor()).To(Equal("http://receptor.myapi.com"))
   180  			})
   181  
   182  			It("clears out existing saved target credentials", func() {
   183  				test_helpers.ExecuteCommandWithArgs(targetCommand, []string{"myapi.com"})
   184  
   185  				Expect(fakeTargetVerifier.VerifyTargetCallCount()).To(Equal(1))
   186  				Expect(fakeTargetVerifier.VerifyTargetArgsForCall(0)).To(Equal("http://receptor.myapi.com"))
   187  			})
   188  
   189  			It("saves the new blob store target", func() {
   190  				fakeBlobStoreVerifier.VerifyReturns(true, nil)
   191  
   192  				test_helpers.ExecuteCommandWithArgs(targetCommand, []string{"myapi.com"})
   193  
   194  				Expect(fakeBlobStoreVerifier.VerifyCallCount()).To(Equal(1))
   195  
   196  				config := fakeBlobStoreVerifier.VerifyArgsForCall(0)
   197  				blobStoreConfig := config.BlobStore()
   198  				Expect(blobStoreConfig).To(Equal(config_package.BlobStoreConfig{
   199  					Host: "myapi.com",
   200  					Port: "8444",
   201  				}))
   202  
   203  				newConfig := config_package.New(configPersister)
   204  				Expect(newConfig.Load()).To(Succeed())
   205  				Expect(newConfig.BlobStore()).To(Equal(config_package.BlobStoreConfig{
   206  					Host: "myapi.com",
   207  					Port: "8444",
   208  				}))
   209  			})
   210  
   211  			Context("when the blob store requires authorization", func() {
   212  				It("exits", func() {
   213  					fakeBlobStoreVerifier.VerifyReturns(false, nil)
   214  
   215  					test_helpers.ExecuteCommandWithArgs(targetCommand, []string{"myapi.com"})
   216  
   217  					Expect(fakeBlobStoreVerifier.VerifyCallCount()).To(Equal(1))
   218  
   219  					config := fakeBlobStoreVerifier.VerifyArgsForCall(0)
   220  					blobStoreConfig := config.BlobStore()
   221  					Expect(blobStoreConfig).To(Equal(config_package.BlobStoreConfig{
   222  						Host: "myapi.com",
   223  						Port: "8444",
   224  					}))
   225  
   226  					Expect(outputBuffer).To(test_helpers.SayLine("Could not authenticate with the droplet store."))
   227  					verifyOldTargetStillSet()
   228  					Expect(fakeExitHandler.ExitCalledWith).To(Equal([]int{exit_codes.BadTarget}))
   229  				})
   230  			})
   231  
   232  			Context("when the blob store target is offline", func() {
   233  				It("exits", func() {
   234  					fakeBlobStoreVerifier.VerifyReturns(false, errors.New("some error"))
   235  
   236  					test_helpers.ExecuteCommandWithArgs(targetCommand, []string{"myapi.com"})
   237  
   238  					Expect(fakeBlobStoreVerifier.VerifyCallCount()).To(Equal(1))
   239  
   240  					config := fakeBlobStoreVerifier.VerifyArgsForCall(0)
   241  					blobStoreConfig := config.BlobStore()
   242  					Expect(blobStoreConfig).To(Equal(config_package.BlobStoreConfig{
   243  						Host: "myapi.com",
   244  						Port: "8444",
   245  					}))
   246  
   247  					Expect(outputBuffer).To(test_helpers.SayLine("Could not connect to the droplet store."))
   248  					verifyOldTargetStillSet()
   249  					Expect(fakeExitHandler.ExitCalledWith).To(Equal([]int{exit_codes.BadTarget}))
   250  				})
   251  			})
   252  
   253  			Context("when the persister returns errors", func() {
   254  				BeforeEach(func() {
   255  					commandFactory := command_factory.NewConfigCommandFactory(config_package.New(errorPersister("some error")), terminalUI, fakeTargetVerifier, fakeBlobStoreVerifier, fakeExitHandler, fakeVersionManager)
   256  					targetCommand = commandFactory.MakeTargetCommand()
   257  				})
   258  
   259  				It("exits", func() {
   260  					test_helpers.ExecuteCommandWithArgs(targetCommand, []string{"myapi.com"})
   261  
   262  					Eventually(outputBuffer).Should(test_helpers.SayLine("some error"))
   263  					verifyOldTargetStillSet()
   264  					Expect(fakeExitHandler.ExitCalledWith).To(Equal([]int{exit_codes.FileSystemError}))
   265  				})
   266  			})
   267  		})
   268  
   269  		Context("when the receptor requires authentication", func() {
   270  			BeforeEach(func() {
   271  				fakeTargetVerifier.VerifyTargetReturns(true, false, nil)
   272  				fakeBlobStoreVerifier.VerifyReturns(true, nil)
   273  				fakePasswordReader.PromptForPasswordReturns("testpassword")
   274  			})
   275  
   276  			It("prompts for credentials and stores them in the config", func() {
   277  				doneChan := test_helpers.AsyncExecuteCommandWithArgs(targetCommand, []string{"myapi.com"})
   278  
   279  				Eventually(outputBuffer).Should(test_helpers.Say("Username: "))
   280  				fakeTargetVerifier.VerifyTargetReturns(true, true, nil)
   281  				stdinWriter.Write([]byte("testusername\n"))
   282  
   283  				Eventually(doneChan, 3).Should(BeClosed())
   284  
   285  				Expect(config.Target()).To(Equal("myapi.com"))
   286  				Expect(config.Receptor()).To(Equal("http://testusername:testpassword@receptor.myapi.com"))
   287  				Expect(outputBuffer).To(test_helpers.SayLine("API location set."))
   288  
   289  				Expect(fakePasswordReader.PromptForPasswordCallCount()).To(Equal(1))
   290  				Expect(fakePasswordReader.PromptForPasswordArgsForCall(0)).To(Equal("Password"))
   291  
   292  				Expect(fakeTargetVerifier.VerifyTargetCallCount()).To(Equal(2))
   293  				Expect(fakeTargetVerifier.VerifyTargetArgsForCall(0)).To(Equal("http://receptor.myapi.com"))
   294  				Expect(fakeTargetVerifier.VerifyTargetArgsForCall(1)).To(Equal("http://testusername:testpassword@receptor.myapi.com"))
   295  			})
   296  
   297  			Context("when provided receptor credentials are invalid", func() {
   298  				It("does not save the config", func() {
   299  					fakePasswordReader.PromptForPasswordReturns("some-invalid-password")
   300  					doneChan := test_helpers.AsyncExecuteCommandWithArgs(targetCommand, []string{"newtarget.com"})
   301  
   302  					Eventually(outputBuffer).Should(test_helpers.Say("Username: "))
   303  					stdinWriter.Write([]byte("some-invalid-user\n"))
   304  
   305  					Eventually(doneChan, 3).Should(BeClosed())
   306  
   307  					Expect(fakePasswordReader.PromptForPasswordCallCount()).To(Equal(1))
   308  					Expect(fakePasswordReader.PromptForPasswordArgsForCall(0)).To(Equal("Password"))
   309  
   310  					Expect(outputBuffer).To(test_helpers.SayLine("Could not authorize target."))
   311  
   312  					verifyOldTargetStillSet()
   313  					Expect(fakeExitHandler.ExitCalledWith).To(Equal([]int{exit_codes.BadTarget}))
   314  				})
   315  			})
   316  
   317  			Context("when the receptor returns an error while verifying the provided credentials", func() {
   318  				It("does not save the config", func() {
   319  					fakePasswordReader.PromptForPasswordReturns("some-invalid-password")
   320  					doneChan := test_helpers.AsyncExecuteCommandWithArgs(targetCommand, []string{"newtarget.com"})
   321  
   322  					Eventually(outputBuffer).Should(test_helpers.Say("Username: "))
   323  
   324  					fakeTargetVerifier.VerifyTargetReturns(true, false, errors.New("Unknown Error"))
   325  					stdinWriter.Write([]byte("some-invalid-user\n"))
   326  
   327  					Eventually(doneChan, 3).Should(BeClosed())
   328  
   329  					Expect(fakePasswordReader.PromptForPasswordCallCount()).To(Equal(1))
   330  					Expect(fakePasswordReader.PromptForPasswordArgsForCall(0)).To(Equal("Password"))
   331  
   332  					Expect(outputBuffer).To(test_helpers.SayLine("Error verifying target: Unknown Error"))
   333  
   334  					verifyOldTargetStillSet()
   335  					Expect(fakeExitHandler.ExitCalledWith).To(Equal([]int{exit_codes.BadTarget}))
   336  				})
   337  			})
   338  
   339  			Context("when the receptor credentials work on the blob store", func() {
   340  				It("saves the new blob store target", func() {
   341  					fakeBlobStoreVerifier.VerifyReturns(true, nil)
   342  
   343  					doneChan := test_helpers.AsyncExecuteCommandWithArgs(targetCommand, []string{"myapi.com"})
   344  
   345  					Eventually(outputBuffer).Should(test_helpers.Say("Username: "))
   346  					fakeTargetVerifier.VerifyTargetReturns(true, true, nil)
   347  					stdinWriter.Write([]byte("testusername\n"))
   348  
   349  					Eventually(doneChan, 3).Should(BeClosed())
   350  
   351  					Expect(fakeBlobStoreVerifier.VerifyCallCount()).To(Equal(1))
   352  
   353  					config := fakeBlobStoreVerifier.VerifyArgsForCall(0)
   354  					blobStoreConfig := config.BlobStore()
   355  					Expect(blobStoreConfig).To(Equal(config_package.BlobStoreConfig{
   356  						Host:     "myapi.com",
   357  						Port:     "8444",
   358  						Username: "testusername",
   359  						Password: "testpassword",
   360  					}))
   361  
   362  					newConfig := config_package.New(configPersister)
   363  					Expect(newConfig.Load()).To(Succeed())
   364  					Expect(newConfig.Receptor()).To(Equal("http://testusername:testpassword@receptor.myapi.com"))
   365  					Expect(newConfig.BlobStore()).To(Equal(config_package.BlobStoreConfig{
   366  						Host:     "myapi.com",
   367  						Port:     "8444",
   368  						Username: "testusername",
   369  						Password: "testpassword",
   370  					}))
   371  				})
   372  			})
   373  
   374  			Context("when the receptor credentials don't work on the blob store", func() {
   375  				It("does not save the config", func() {
   376  					fakeBlobStoreVerifier.VerifyReturns(false, nil)
   377  
   378  					doneChan := test_helpers.AsyncExecuteCommandWithArgs(targetCommand, []string{"myapi.com"})
   379  
   380  					Eventually(outputBuffer).Should(test_helpers.Say("Username: "))
   381  					fakeTargetVerifier.VerifyTargetReturns(true, true, nil)
   382  					stdinWriter.Write([]byte("testusername\n"))
   383  
   384  					Eventually(doneChan, 3).Should(BeClosed())
   385  
   386  					Expect(fakeBlobStoreVerifier.VerifyCallCount()).To(Equal(1))
   387  
   388  					config := fakeBlobStoreVerifier.VerifyArgsForCall(0)
   389  					blobStoreConfig := config.BlobStore()
   390  					Expect(blobStoreConfig).To(Equal(config_package.BlobStoreConfig{
   391  						Host:     "myapi.com",
   392  						Port:     "8444",
   393  						Username: "testusername",
   394  						Password: "testpassword",
   395  					}))
   396  
   397  					Expect(outputBuffer).To(test_helpers.SayLine("Could not authenticate with the droplet store."))
   398  					verifyOldTargetStillSet()
   399  					Expect(fakeExitHandler.ExitCalledWith).To(Equal([]int{exit_codes.BadTarget}))
   400  				})
   401  			})
   402  
   403  			Context("when the blob store is offline", func() {
   404  				It("does not save the config", func() {
   405  					fakeBlobStoreVerifier.VerifyReturns(false, errors.New("some error"))
   406  
   407  					doneChan := test_helpers.AsyncExecuteCommandWithArgs(targetCommand, []string{"myapi.com"})
   408  
   409  					Eventually(outputBuffer).Should(test_helpers.Say("Username: "))
   410  					fakeTargetVerifier.VerifyTargetReturns(true, true, nil)
   411  					stdinWriter.Write([]byte("testusername\n"))
   412  
   413  					Eventually(doneChan, 3).Should(BeClosed())
   414  
   415  					Expect(fakeBlobStoreVerifier.VerifyCallCount()).To(Equal(1))
   416  
   417  					config := fakeBlobStoreVerifier.VerifyArgsForCall(0)
   418  					blobStoreConfig := config.BlobStore()
   419  					Expect(blobStoreConfig).To(Equal(config_package.BlobStoreConfig{
   420  						Host:     "myapi.com",
   421  						Port:     "8444",
   422  						Username: "testusername",
   423  						Password: "testpassword",
   424  					}))
   425  
   426  					Expect(outputBuffer).To(test_helpers.SayLine("Could not connect to the droplet store."))
   427  					verifyOldTargetStillSet()
   428  					Expect(fakeExitHandler.ExitCalledWith).To(Equal([]int{exit_codes.BadTarget}))
   429  				})
   430  			})
   431  		})
   432  
   433  		Context("s3", func() {
   434  			It("prompts for s3 configuration when --s3 is passed", func() {
   435  				fakeTargetVerifier.VerifyTargetReturns(true, true, nil)
   436  				fakeBlobStoreVerifier.VerifyReturns(true, nil)
   437  				fakePasswordReader.PromptForPasswordReturns("some-secret")
   438  
   439  				doneChan := test_helpers.AsyncExecuteCommandWithArgs(targetCommand, []string{"myapi.com", "--s3"})
   440  
   441  				Eventually(outputBuffer).Should(test_helpers.Say("S3 Access Key: "))
   442  				stdinWriter.Write([]byte("some-access\n"))
   443  				Eventually(outputBuffer).Should(test_helpers.Say("S3 Bucket: "))
   444  				stdinWriter.Write([]byte("some-bucket\n"))
   445  				Eventually(outputBuffer).Should(test_helpers.Say("S3 Region: "))
   446  				stdinWriter.Write([]byte("some-region\n"))
   447  
   448  				Eventually(doneChan, 3).Should(BeClosed())
   449  
   450  				Expect(fakeBlobStoreVerifier.VerifyCallCount()).To(Equal(1))
   451  				config := fakeBlobStoreVerifier.VerifyArgsForCall(0)
   452  				s3BlobTargetInfo := config.S3BlobStore()
   453  				Expect(s3BlobTargetInfo.AccessKey).To(Equal("some-access"))
   454  				Expect(s3BlobTargetInfo.SecretKey).To(Equal("some-secret"))
   455  				Expect(s3BlobTargetInfo.BucketName).To(Equal("some-bucket"))
   456  				Expect(s3BlobTargetInfo.Region).To(Equal("some-region"))
   457  
   458  				newConfig := config_package.New(configPersister)
   459  				Expect(newConfig.Load()).To(Succeed())
   460  				newS3BlobTargetInfo := newConfig.S3BlobStore()
   461  				Expect(newS3BlobTargetInfo.AccessKey).To(Equal("some-access"))
   462  				Expect(newS3BlobTargetInfo.SecretKey).To(Equal("some-secret"))
   463  				Expect(newS3BlobTargetInfo.BucketName).To(Equal("some-bucket"))
   464  				Expect(newS3BlobTargetInfo.Region).To(Equal("some-region"))
   465  			})
   466  		})
   467  
   468  		Context("setting an invalid target", func() {
   469  			It("does not save the config", func() {
   470  				fakeTargetVerifier.VerifyTargetReturns(true, false, errors.New("Unknown Error"))
   471  
   472  				test_helpers.ExecuteCommandWithArgs(targetCommand, []string{"newtarget.com"})
   473  
   474  				Expect(outputBuffer).To(test_helpers.SayLine("Error verifying target: Unknown Error"))
   475  
   476  				verifyOldTargetStillSet()
   477  				Expect(fakeExitHandler.ExitCalledWith).To(Equal([]int{exit_codes.BadTarget}))
   478  			})
   479  		})
   480  
   481  		Context("checking ltc target version", func() {
   482  			BeforeEach(func() {
   483  				fakeTargetVerifier.VerifyTargetReturns(true, true, nil)
   484  				fakeBlobStoreVerifier.VerifyReturns(true, nil)
   485  				fakeVersionManager.LatticeVersionReturns("some-version")
   486  			})
   487  
   488  			It("should print warning and recommend sync if ltc version does not match server", func() {
   489  				fakeVersionManager.LtcMatchesServerReturns(false, nil)
   490  
   491  				test_helpers.ExecuteCommandWithArgs(targetCommand, []string{"target.com"})
   492  
   493  				Expect(fakeVersionManager.LtcMatchesServerCallCount()).To(Equal(1))
   494  				Expect(fakeVersionManager.LtcMatchesServerArgsForCall(0)).To(Equal("http://receptor.target.com"))
   495  
   496  				Expect(outputBuffer).To(test_helpers.SayLine("WARNING: local ltc version (some-version) does not match target expected version."))
   497  				Expect(outputBuffer).To(test_helpers.SayLine("Run `ltc sync` to replace your local ltc command-line tool with your target cluster's expected version."))
   498  			})
   499  
   500  			It("should print warning and NOT recommend sync if ServerVersions endpoint fails", func() {
   501  				fakeVersionManager.LtcMatchesServerReturns(false, errors.New("whoops"))
   502  
   503  				test_helpers.ExecuteCommandWithArgs(targetCommand, []string{"target.com"})
   504  
   505  				Expect(fakeVersionManager.LtcMatchesServerCallCount()).To(Equal(1))
   506  				Expect(fakeVersionManager.LtcMatchesServerArgsForCall(0)).To(Equal("http://receptor.target.com"))
   507  
   508  				Expect(outputBuffer).To(test_helpers.SayLine("WARNING: local ltc version (some-version) does not match target expected version."))
   509  				Expect(outputBuffer).NotTo(test_helpers.SayLine("Run `ltc sync` to replace your local ltc command-line tool with your target cluster's expected version."))
   510  			})
   511  
   512  			It("should not print an error if ltc version matches server", func() {
   513  				fakeVersionManager.LtcMatchesServerReturns(true, nil)
   514  
   515  				test_helpers.ExecuteCommandWithArgs(targetCommand, []string{"target.com"})
   516  
   517  				Expect(fakeVersionManager.LtcMatchesServerCallCount()).To(Equal(1))
   518  				Expect(fakeVersionManager.LtcMatchesServerArgsForCall(0)).To(Equal("http://receptor.target.com"))
   519  
   520  				Expect(outputBuffer).NotTo(test_helpers.SayLine("WARNING: local ltc version (some-version) does not match target expected version."))
   521  				Expect(outputBuffer).NotTo(test_helpers.SayLine("Run `ltc sync` to replace your local ltc command-line tool with your target cluster's expected version."))
   522  			})
   523  		})
   524  	})
   525  })
   526  
   527  type errorPersister string
   528  
   529  func (f errorPersister) Load(i interface{}) error {
   530  	return errors.New(string(f))
   531  }
   532  
   533  func (f errorPersister) Save(i interface{}) error {
   534  	return errors.New(string(f))
   535  }