github.com/pivotal-cf/go-pivnet/v6@v6.0.2/artifact_references_test.go (about)

     1  package pivnet_test
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/onsi/gomega/ghttp"
     6  	"github.com/pivotal-cf/go-pivnet/v6"
     7  	"github.com/pivotal-cf/go-pivnet/v6/go-pivnetfakes"
     8  	"github.com/pivotal-cf/go-pivnet/v6/logger"
     9  	"github.com/pivotal-cf/go-pivnet/v6/logger/loggerfakes"
    10  	"net/http"
    11  
    12  	. "github.com/onsi/ginkgo"
    13  	. "github.com/onsi/gomega"
    14  )
    15  
    16  var _ = Describe("PivnetClient - artifact references", func() {
    17  	var (
    18  		server     *ghttp.Server
    19  		client     pivnet.Client
    20  		apiAddress string
    21  		userAgent  string
    22  
    23  		newClientConfig        pivnet.ClientConfig
    24  		fakeLogger             logger.Logger
    25  		fakeAccessTokenService *gopivnetfakes.FakeAccessTokenService
    26  	)
    27  
    28  	BeforeEach(func() {
    29  		server = ghttp.NewServer()
    30  		apiAddress = server.URL()
    31  		userAgent = "pivnet-resource/0.1.0 (some-url)"
    32  
    33  		fakeLogger = &loggerfakes.FakeLogger{}
    34  		fakeAccessTokenService = &gopivnetfakes.FakeAccessTokenService{}
    35  		newClientConfig = pivnet.ClientConfig{
    36  			Host:      apiAddress,
    37  			UserAgent: userAgent,
    38  		}
    39  		client = pivnet.NewClient(fakeAccessTokenService, newClientConfig, fakeLogger)
    40  	})
    41  
    42  	AfterEach(func() {
    43  		server.Close()
    44  	})
    45  
    46  	Describe("List artifact references", func() {
    47  		var (
    48  			productSlug string
    49  
    50  			response           interface{}
    51  			responseStatusCode int
    52  		)
    53  
    54  		BeforeEach(func() {
    55  			productSlug = "banana"
    56  
    57  			response = pivnet.ArtifactReferencesResponse{[]pivnet.ArtifactReference{
    58  				{
    59  					ID:   1234,
    60  					Name: "something",
    61  				},
    62  				{
    63  					ID:   2345,
    64  					Name: "something-else",
    65  				},
    66  			}}
    67  
    68  			responseStatusCode = http.StatusOK
    69  		})
    70  
    71  		JustBeforeEach(func() {
    72  			server.AppendHandlers(
    73  				ghttp.CombineHandlers(
    74  					ghttp.VerifyRequest(
    75  						"GET",
    76  						fmt.Sprintf(
    77  							"%s/products/%s/artifact_references",
    78  							apiPrefix,
    79  							productSlug,
    80  						),
    81  					),
    82  					ghttp.RespondWithJSONEncoded(responseStatusCode, response),
    83  				),
    84  			)
    85  		})
    86  
    87  		It("returns the artifact references without error", func() {
    88  			artifactReferences, err := client.ArtifactReferences.List(
    89  				productSlug,
    90  			)
    91  			Expect(err).NotTo(HaveOccurred())
    92  
    93  			Expect(artifactReferences).To(HaveLen(2))
    94  			Expect(artifactReferences[0].ID).To(Equal(1234))
    95  		})
    96  
    97  		Context("when the server responds with a non-2XX status code", func() {
    98  			BeforeEach(func() {
    99  				responseStatusCode = http.StatusTeapot
   100  				response = pivnetErr{Message: "foo message"}
   101  			})
   102  
   103  			It("returns an error", func() {
   104  				_, err := client.ArtifactReferences.List(
   105  					productSlug,
   106  				)
   107  				Expect(err).To(HaveOccurred())
   108  
   109  				Expect(err.Error()).To(ContainSubstring("foo message"))
   110  			})
   111  		})
   112  
   113  		Context("when the json unmarshalling fails with error", func() {
   114  			BeforeEach(func() {
   115  				response = "%%%"
   116  			})
   117  
   118  			It("forwards the error", func() {
   119  				_, err := client.ArtifactReferences.List(
   120  					productSlug,
   121  				)
   122  				Expect(err).To(HaveOccurred())
   123  
   124  				Expect(err.Error()).To(ContainSubstring("json"))
   125  			})
   126  		})
   127  	})
   128  
   129  	Describe("List artifact references for specific digest", func() {
   130  		var (
   131  			productSlug string
   132  			digest      string
   133  
   134  			response           interface{}
   135  			responseStatusCode int
   136  		)
   137  
   138  		BeforeEach(func() {
   139  			productSlug = "banana"
   140  			digest = "sha256:digest"
   141  
   142  			response = pivnet.ArtifactReferencesResponse{[]pivnet.ArtifactReference{
   143  				{
   144  					ID:   1234,
   145  					Name: "something",
   146  				},
   147  				{
   148  					ID:   2345,
   149  					Name: "something-else",
   150  					ReleaseVersions: []string{"1.0.0","1.2.3"},
   151  				},
   152  			}}
   153  
   154  			responseStatusCode = http.StatusOK
   155  		})
   156  
   157  		JustBeforeEach(func() {
   158  			server.AppendHandlers(
   159  				ghttp.CombineHandlers(
   160  					ghttp.VerifyRequest(
   161  						"GET",
   162  						fmt.Sprintf(
   163  							"%s/products/%s/artifact_references",
   164  							apiPrefix,
   165  							productSlug,
   166  						),
   167  						"digest=sha256:digest",
   168  					),
   169  					ghttp.RespondWithJSONEncoded(responseStatusCode, response),
   170  				),
   171  			)
   172  		})
   173  
   174  		It("returns the artifact references without error", func() {
   175  			artifactReferences, err := client.ArtifactReferences.ListForDigest(
   176  				productSlug,
   177  				digest,
   178  			)
   179  			Expect(err).NotTo(HaveOccurred())
   180  
   181  			Expect(artifactReferences).To(HaveLen(2))
   182  			Expect(artifactReferences[0].ID).To(Equal(1234))
   183  			Expect(artifactReferences[1].ReleaseVersions).To(HaveLen(2))
   184  			Expect(artifactReferences[1].ReleaseVersions[0]).To(Equal("1.0.0"))
   185  			Expect(artifactReferences[1].ReleaseVersions[1]).To(Equal("1.2.3"))
   186  		})
   187  
   188  		Context("when the server responds with a non-2XX status code", func() {
   189  			BeforeEach(func() {
   190  				responseStatusCode = http.StatusTeapot
   191  				response = pivnetErr{Message: "foo message"}
   192  			})
   193  
   194  			It("returns an error", func() {
   195  				_, err := client.ArtifactReferences.ListForDigest(
   196  					productSlug,
   197  					digest,
   198  				)
   199  				Expect(err).To(HaveOccurred())
   200  
   201  				Expect(err.Error()).To(ContainSubstring("foo message"))
   202  			})
   203  		})
   204  
   205  		Context("when the json unmarshalling fails with error", func() {
   206  			BeforeEach(func() {
   207  				response = "%%%"
   208  			})
   209  
   210  			It("forwards the error", func() {
   211  				_, err := client.ArtifactReferences.ListForDigest(
   212  					productSlug,
   213  					digest,
   214  				)
   215  				Expect(err).To(HaveOccurred())
   216  
   217  				Expect(err.Error()).To(ContainSubstring("json"))
   218  			})
   219  		})
   220  	})
   221  
   222  	Describe("List artifact references for release", func() {
   223  		var (
   224  			productSlug string
   225  			releaseID   int
   226  
   227  			response           interface{}
   228  			responseStatusCode int
   229  		)
   230  
   231  		BeforeEach(func() {
   232  			productSlug = "banana"
   233  			releaseID = 12
   234  
   235  			response = pivnet.ArtifactReferencesResponse{[]pivnet.ArtifactReference{
   236  				{
   237  					ID:   1234,
   238  					Name: "something",
   239  				},
   240  				{
   241  					ID:   2345,
   242  					Name: "something-else",
   243  				},
   244  			}}
   245  
   246  			responseStatusCode = http.StatusOK
   247  		})
   248  
   249  		JustBeforeEach(func() {
   250  			server.AppendHandlers(
   251  				ghttp.CombineHandlers(
   252  					ghttp.VerifyRequest(
   253  						"GET",
   254  						fmt.Sprintf(
   255  							"%s/products/%s/releases/%d/artifact_references",
   256  							apiPrefix,
   257  							productSlug,
   258  							releaseID,
   259  						),
   260  					),
   261  					ghttp.RespondWithJSONEncoded(responseStatusCode, response),
   262  				),
   263  			)
   264  		})
   265  
   266  		It("returns the artifact references without error", func() {
   267  			artifactReferences, err := client.ArtifactReferences.ListForRelease(
   268  				productSlug,
   269  				releaseID,
   270  			)
   271  			Expect(err).NotTo(HaveOccurred())
   272  
   273  			Expect(artifactReferences).To(HaveLen(2))
   274  			Expect(artifactReferences[0].ID).To(Equal(1234))
   275  		})
   276  
   277  		Context("when the server responds with a non-2XX status code", func() {
   278  			BeforeEach(func() {
   279  				responseStatusCode = http.StatusTeapot
   280  				response = pivnetErr{Message: "foo message"}
   281  			})
   282  
   283  			It("returns an error", func() {
   284  				_, err := client.ArtifactReferences.ListForRelease(
   285  					productSlug,
   286  					releaseID,
   287  				)
   288  				Expect(err).To(HaveOccurred())
   289  
   290  				Expect(err.Error()).To(ContainSubstring("foo message"))
   291  			})
   292  		})
   293  
   294  		Context("when the json unmarshalling fails with error", func() {
   295  			BeforeEach(func() {
   296  				response = "%%%"
   297  			})
   298  
   299  			It("forwards the error", func() {
   300  				_, err := client.ArtifactReferences.ListForRelease(
   301  					productSlug,
   302  					releaseID,
   303  				)
   304  				Expect(err).To(HaveOccurred())
   305  
   306  				Expect(err.Error()).To(ContainSubstring("json"))
   307  			})
   308  		})
   309  	})
   310  
   311  	Describe("Get artifact Reference", func() {
   312  		var (
   313  			productSlug         string
   314  			artifactReferenceID int
   315  
   316  			response           interface{}
   317  			responseStatusCode int
   318  		)
   319  
   320  		BeforeEach(func() {
   321  			productSlug = "banana"
   322  			artifactReferenceID = 1234
   323  
   324  			response = pivnet.ArtifactReferenceResponse{
   325  				ArtifactReference: pivnet.ArtifactReference{
   326  					ID:   artifactReferenceID,
   327  					Name: "something",
   328  				}}
   329  
   330  			responseStatusCode = http.StatusOK
   331  		})
   332  
   333  		JustBeforeEach(func() {
   334  			server.AppendHandlers(
   335  				ghttp.CombineHandlers(
   336  					ghttp.VerifyRequest(
   337  						"GET",
   338  						fmt.Sprintf(
   339  							"%s/products/%s/artifact_references/%d",
   340  							apiPrefix,
   341  							productSlug,
   342  							artifactReferenceID,
   343  						),
   344  					),
   345  					ghttp.RespondWithJSONEncoded(responseStatusCode, response),
   346  				),
   347  			)
   348  		})
   349  
   350  		It("returns the artifact reference without error", func() {
   351  			artifactReference, err := client.ArtifactReferences.Get(
   352  				productSlug,
   353  				artifactReferenceID,
   354  			)
   355  			Expect(err).NotTo(HaveOccurred())
   356  
   357  			Expect(artifactReference.ID).To(Equal(artifactReferenceID))
   358  			Expect(artifactReference.Name).To(Equal("something"))
   359  		})
   360  
   361  		Context("when the server responds with a non-2XX status code", func() {
   362  			BeforeEach(func() {
   363  				responseStatusCode = http.StatusTeapot
   364  				response = pivnetErr{Message: "foo message"}
   365  			})
   366  
   367  			It("returns an error", func() {
   368  				_, err := client.ArtifactReferences.Get(
   369  					productSlug,
   370  					artifactReferenceID,
   371  				)
   372  				Expect(err).To(HaveOccurred())
   373  
   374  				Expect(err.Error()).To(ContainSubstring("foo message"))
   375  			})
   376  		})
   377  
   378  		Context("when the json unmarshalling fails with error", func() {
   379  			BeforeEach(func() {
   380  				response = "%%%"
   381  			})
   382  
   383  			It("forwards the error", func() {
   384  				_, err := client.ArtifactReferences.Get(
   385  					productSlug,
   386  					artifactReferenceID,
   387  				)
   388  				Expect(err).To(HaveOccurred())
   389  
   390  				Expect(err.Error()).To(ContainSubstring("json"))
   391  			})
   392  		})
   393  	})
   394  
   395  	Describe("Get artifact reference for release", func() {
   396  		var (
   397  			productSlug         string
   398  			releaseID           int
   399  			artifactReferenceID int
   400  
   401  			response           interface{}
   402  			responseStatusCode int
   403  		)
   404  
   405  		BeforeEach(func() {
   406  			productSlug = "banana"
   407  			releaseID = 12
   408  			artifactReferenceID = 1234
   409  
   410  			response = pivnet.ArtifactReferenceResponse{
   411  				ArtifactReference: pivnet.ArtifactReference{
   412  					ID:   artifactReferenceID,
   413  					Name: "something",
   414  				}}
   415  
   416  			responseStatusCode = http.StatusOK
   417  		})
   418  
   419  		JustBeforeEach(func() {
   420  			server.AppendHandlers(
   421  				ghttp.CombineHandlers(
   422  					ghttp.VerifyRequest(
   423  						"GET",
   424  						fmt.Sprintf(
   425  							"%s/products/%s/releases/%d/artifact_references/%d",
   426  							apiPrefix,
   427  							productSlug,
   428  							releaseID,
   429  							artifactReferenceID,
   430  						),
   431  					),
   432  					ghttp.RespondWithJSONEncoded(responseStatusCode, response),
   433  				),
   434  			)
   435  		})
   436  
   437  		It("returns the artifact reference without error", func() {
   438  			artifactReference, err := client.ArtifactReferences.GetForRelease(
   439  				productSlug,
   440  				releaseID,
   441  				artifactReferenceID,
   442  			)
   443  			Expect(err).NotTo(HaveOccurred())
   444  
   445  			Expect(artifactReference.ID).To(Equal(artifactReferenceID))
   446  			Expect(artifactReference.Name).To(Equal("something"))
   447  		})
   448  
   449  		Context("when the server responds with a non-2XX status code", func() {
   450  			BeforeEach(func() {
   451  				responseStatusCode = http.StatusTeapot
   452  				response = pivnetErr{Message: "foo message"}
   453  			})
   454  
   455  			It("returns an error", func() {
   456  				_, err := client.ArtifactReferences.GetForRelease(
   457  					productSlug,
   458  					releaseID,
   459  					artifactReferenceID,
   460  				)
   461  				Expect(err).To(HaveOccurred())
   462  
   463  				Expect(err.Error()).To(ContainSubstring("foo message"))
   464  			})
   465  		})
   466  
   467  		Context("when the json unmarshalling fails with error", func() {
   468  			BeforeEach(func() {
   469  				response = "%%%"
   470  			})
   471  
   472  			It("forwards the error", func() {
   473  				_, err := client.ArtifactReferences.GetForRelease(
   474  					productSlug,
   475  					releaseID,
   476  					artifactReferenceID,
   477  				)
   478  				Expect(err).To(HaveOccurred())
   479  
   480  				Expect(err.Error()).To(ContainSubstring("json"))
   481  			})
   482  		})
   483  	})
   484  
   485  	Describe("Create Artifact Reference", func() {
   486  		type requestBody struct {
   487  			ArtifactReference pivnet.ArtifactReference `json:"artifact_reference"`
   488  		}
   489  
   490  		var (
   491  			createArtifactReferenceConfig pivnet.CreateArtifactReferenceConfig
   492  
   493  			expectedRequestBody requestBody
   494  
   495  			artifactReferenceResponse pivnet.ArtifactReferenceResponse
   496  		)
   497  
   498  		BeforeEach(func() {
   499  			createArtifactReferenceConfig = pivnet.CreateArtifactReferenceConfig{
   500  				ProductSlug:        productSlug,
   501  				Description:        "some\nmulti-line\ndescription",
   502  				Digest:             "sha256:mydigest",
   503  				DocsURL:            "some-docs-url",
   504  				ArtifactPath:       "my/path:123",
   505  				Name:               "some-artifact-name",
   506  				SystemRequirements: []string{"system-1", "system-2"},
   507  			}
   508  
   509  			expectedRequestBody = requestBody{
   510  				ArtifactReference: pivnet.ArtifactReference{
   511  					Description:        createArtifactReferenceConfig.Description,
   512  					Digest:             createArtifactReferenceConfig.Digest,
   513  					DocsURL:            createArtifactReferenceConfig.DocsURL,
   514  					ArtifactPath:       createArtifactReferenceConfig.ArtifactPath,
   515  					Name:               createArtifactReferenceConfig.Name,
   516  					SystemRequirements: createArtifactReferenceConfig.SystemRequirements,
   517  				},
   518  			}
   519  
   520  			artifactReferenceResponse = pivnet.ArtifactReferenceResponse{
   521  				ArtifactReference: pivnet.ArtifactReference{
   522  					ID:                 1234,
   523  					Description:        createArtifactReferenceConfig.Description,
   524  					Digest:             createArtifactReferenceConfig.Digest,
   525  					DocsURL:            createArtifactReferenceConfig.DocsURL,
   526  					ArtifactPath:       createArtifactReferenceConfig.ArtifactPath,
   527  					Name:               createArtifactReferenceConfig.Name,
   528  					SystemRequirements: createArtifactReferenceConfig.SystemRequirements,
   529  					ReplicationStatus:  pivnet.InProgress,
   530  				}}
   531  		})
   532  
   533  		It("creates the artifact reference", func() {
   534  			server.AppendHandlers(
   535  				ghttp.CombineHandlers(
   536  					ghttp.VerifyRequest("POST", fmt.Sprintf(
   537  						"%s/products/%s/artifact_references",
   538  						apiPrefix,
   539  						productSlug,
   540  					)),
   541  					ghttp.VerifyJSONRepresenting(&expectedRequestBody),
   542  					ghttp.RespondWithJSONEncoded(http.StatusCreated, artifactReferenceResponse),
   543  				),
   544  			)
   545  
   546  			artifactReference, err := client.ArtifactReferences.Create(createArtifactReferenceConfig)
   547  			Expect(err).NotTo(HaveOccurred())
   548  			Expect(artifactReference.ID).To(Equal(1234))
   549  			Expect(artifactReference).To(Equal(artifactReferenceResponse.ArtifactReference))
   550  		})
   551  
   552  		Context("when the server responds with a non-201 status code", func() {
   553  			var (
   554  				response interface{}
   555  			)
   556  
   557  			BeforeEach(func() {
   558  				response = pivnetErr{Message: "foo message"}
   559  			})
   560  
   561  			It("returns an error", func() {
   562  				server.AppendHandlers(
   563  					ghttp.CombineHandlers(
   564  						ghttp.VerifyRequest("POST", fmt.Sprintf(
   565  							"%s/products/%s/artifact_references",
   566  							apiPrefix,
   567  							productSlug,
   568  						)),
   569  						ghttp.RespondWithJSONEncoded(http.StatusTeapot, response),
   570  					),
   571  				)
   572  
   573  				_, err := client.ArtifactReferences.Create(createArtifactReferenceConfig)
   574  				Expect(err.Error()).To(ContainSubstring("foo message"))
   575  			})
   576  		})
   577  
   578  		Context("when the server responds with a 429 status code", func() {
   579  			It("returns an error indicating the limit was hit", func() {
   580  				server.AppendHandlers(
   581  					ghttp.CombineHandlers(
   582  						ghttp.VerifyRequest("POST", fmt.Sprintf(
   583  							"%s/products/%s/artifact_references",
   584  							apiPrefix,
   585  							productSlug,
   586  						)),
   587  						ghttp.RespondWith(http.StatusTooManyRequests, "Retry later"),
   588  					),
   589  				)
   590  
   591  				_, err := client.ArtifactReferences.Create(createArtifactReferenceConfig)
   592  				Expect(err.Error()).To(ContainSubstring("You have hit the artifact reference creation limit. Please wait before creating more artifact references. Contact pivnet-eng@pivotal.io with additional questions."))
   593  			})
   594  		})
   595  
   596  		Context("when the json unmarshalling fails with error", func() {
   597  			It("forwards the error", func() {
   598  				server.AppendHandlers(
   599  					ghttp.CombineHandlers(
   600  						ghttp.VerifyRequest("POST", fmt.Sprintf(
   601  							"%s/products/%s/artifact_references",
   602  							apiPrefix,
   603  							productSlug,
   604  						)),
   605  						ghttp.RespondWith(http.StatusTeapot, "%%%"),
   606  					),
   607  				)
   608  
   609  				_, err := client.ArtifactReferences.Create(createArtifactReferenceConfig)
   610  				Expect(err).To(HaveOccurred())
   611  
   612  				Expect(err.Error()).To(ContainSubstring("invalid character"))
   613  			})
   614  		})
   615  	})
   616  
   617  	Describe("Update artifact reference", func() {
   618  		type requestBody struct {
   619  			ArtifactReference pivnet.ArtifactReference `json:"artifact_reference"`
   620  		}
   621  
   622  		var (
   623  			expectedRequestBody        requestBody
   624  			artifactReference          pivnet.ArtifactReference
   625  			updateArtifactReferenceUrl string
   626  			validResponse              = `{"artifact_reference":{"id":1234, "docs_url":"example.io", "system_requirements": ["1", "2"], "replication_status": "in_progress"}}`
   627  		)
   628  
   629  		BeforeEach(func() {
   630  			artifactReference = pivnet.ArtifactReference{
   631  				ID:                 1234,
   632  				ArtifactPath:       "some/path",
   633  				Description:        "Avast! Pieces o' passion are forever fine.",
   634  				Digest:             "some-sha265",
   635  				DocsURL:            "example.io",
   636  				Name:               "turpis-hercle",
   637  				SystemRequirements: []string{"1", "2"},
   638  			}
   639  
   640  			expectedRequestBody = requestBody{
   641  				ArtifactReference: pivnet.ArtifactReference{
   642  					Description:        artifactReference.Description,
   643  					Name:               artifactReference.Name,
   644  					DocsURL:            artifactReference.DocsURL,
   645  					SystemRequirements: artifactReference.SystemRequirements,
   646  				},
   647  			}
   648  
   649  			updateArtifactReferenceUrl = fmt.Sprintf(
   650  				"%s/products/%s/artifact_references/%d",
   651  				apiPrefix,
   652  				productSlug,
   653  				artifactReference.ID,
   654  			)
   655  
   656  		})
   657  
   658  		It("updates the artifact reference with the provided fields", func() {
   659  			server.AppendHandlers(
   660  				ghttp.CombineHandlers(
   661  					ghttp.VerifyRequest("PATCH", updateArtifactReferenceUrl),
   662  					ghttp.VerifyJSONRepresenting(&expectedRequestBody),
   663  					ghttp.RespondWith(http.StatusOK, validResponse),
   664  				),
   665  			)
   666  
   667  			updatedArtifactReference, err := client.ArtifactReferences.Update(productSlug, artifactReference)
   668  			Expect(err).NotTo(HaveOccurred())
   669  			Expect(updatedArtifactReference.ID).To(Equal(artifactReference.ID))
   670  			Expect(updatedArtifactReference.DocsURL).To(Equal(artifactReference.DocsURL))
   671  			Expect(updatedArtifactReference.SystemRequirements).To(ConsistOf("2", "1"))
   672  			Expect(updatedArtifactReference.ReplicationStatus).To(Equal(pivnet.InProgress))
   673  		})
   674  
   675  		It("forwards the server-side error", func() {
   676  			server.AppendHandlers(
   677  				ghttp.CombineHandlers(
   678  					ghttp.VerifyRequest("PATCH", updateArtifactReferenceUrl),
   679  					ghttp.RespondWithJSONEncoded(http.StatusTeapot,
   680  						pivnetErr{Message: "Meet, scotty, powerdrain!"}),
   681  				),
   682  			)
   683  
   684  			_, err := client.ArtifactReferences.Update(productSlug, artifactReference)
   685  
   686  			Expect(err).To(HaveOccurred())
   687  			Expect(err.Error()).To(ContainSubstring("scotty"))
   688  		})
   689  
   690  		It("forwards the unmarshalling error", func() {
   691  			server.AppendHandlers(
   692  				ghttp.CombineHandlers(
   693  					ghttp.VerifyRequest("PATCH", updateArtifactReferenceUrl),
   694  					ghttp.RespondWith(http.StatusTeapot, "<NOT></JSON>"),
   695  				),
   696  			)
   697  			_, err := client.ArtifactReferences.Update(productSlug, artifactReference)
   698  
   699  			Expect(err).To(HaveOccurred())
   700  			Expect(err.Error()).To(ContainSubstring("invalid character"))
   701  		})
   702  	})
   703  
   704  	Describe("Delete Artifact Reference", func() {
   705  		var (
   706  			id = 1234
   707  		)
   708  
   709  		It("deletes the artifact reference", func() {
   710  			response := []byte(`{"artifact_reference":{"id":1234}}`)
   711  
   712  			server.AppendHandlers(
   713  				ghttp.CombineHandlers(
   714  					ghttp.VerifyRequest(
   715  						"DELETE",
   716  						fmt.Sprintf("%s/products/%s/artifact_references/%d", apiPrefix, productSlug, id)),
   717  					ghttp.RespondWith(http.StatusOK, response),
   718  				),
   719  			)
   720  
   721  			artifactReference, err := client.ArtifactReferences.Delete(productSlug, id)
   722  			Expect(err).NotTo(HaveOccurred())
   723  
   724  			Expect(artifactReference.ID).To(Equal(id))
   725  		})
   726  
   727  		Context("when the server responds with a non-2XX status code", func() {
   728  			var (
   729  				response interface{}
   730  			)
   731  
   732  			BeforeEach(func() {
   733  				response = pivnetErr{Message: "foo message"}
   734  			})
   735  
   736  			It("returns an error", func() {
   737  				server.AppendHandlers(
   738  					ghttp.CombineHandlers(
   739  						ghttp.VerifyRequest(
   740  							"DELETE",
   741  							fmt.Sprintf("%s/products/%s/artifact_references/%d", apiPrefix, productSlug, id)),
   742  						ghttp.RespondWithJSONEncoded(http.StatusTeapot, response),
   743  					),
   744  				)
   745  
   746  				_, err := client.ArtifactReferences.Delete(productSlug, id)
   747  				Expect(err.Error()).To(ContainSubstring("foo message"))
   748  			})
   749  		})
   750  
   751  		Context("when the json unmarshalling fails with error", func() {
   752  			It("forwards the error", func() {
   753  				server.AppendHandlers(
   754  					ghttp.CombineHandlers(
   755  						ghttp.VerifyRequest(
   756  							"DELETE",
   757  							fmt.Sprintf("%s/products/%s/artifact_references/%d", apiPrefix, productSlug, id)),
   758  						ghttp.RespondWith(http.StatusTeapot, "%%%"),
   759  					),
   760  				)
   761  
   762  				_, err := client.ArtifactReferences.Delete(productSlug, id)
   763  				Expect(err).To(HaveOccurred())
   764  
   765  				Expect(err.Error()).To(ContainSubstring("invalid character"))
   766  			})
   767  		})
   768  	})
   769  
   770  	Describe("Add Artifact Reference to release", func() {
   771  		var (
   772  			productSlug         = "some-product"
   773  			releaseID           = 2345
   774  			artifactReferenceID = 3456
   775  
   776  			expectedRequestBody = `{"artifact_reference":{"id":3456}}`
   777  		)
   778  
   779  		Context("when the server responds with a 204 status code", func() {
   780  			It("returns without error", func() {
   781  				server.AppendHandlers(
   782  					ghttp.CombineHandlers(
   783  						ghttp.VerifyRequest("PATCH", fmt.Sprintf(
   784  							"%s/products/%s/releases/%d/add_artifact_reference",
   785  							apiPrefix,
   786  							productSlug,
   787  							releaseID,
   788  						)),
   789  						ghttp.VerifyJSON(expectedRequestBody),
   790  						ghttp.RespondWith(http.StatusNoContent, nil),
   791  					),
   792  				)
   793  
   794  				err := client.ArtifactReferences.AddToRelease(productSlug, releaseID, artifactReferenceID)
   795  				Expect(err).NotTo(HaveOccurred())
   796  			})
   797  		})
   798  
   799  		Context("when the server responds with a non-204 status code", func() {
   800  			var (
   801  				response interface{}
   802  			)
   803  
   804  			BeforeEach(func() {
   805  				response = pivnetErr{Message: "foo message"}
   806  			})
   807  
   808  			It("returns an error", func() {
   809  				server.AppendHandlers(
   810  					ghttp.CombineHandlers(
   811  						ghttp.VerifyRequest("PATCH", fmt.Sprintf(
   812  							"%s/products/%s/releases/%d/add_artifact_reference",
   813  							apiPrefix,
   814  							productSlug,
   815  							releaseID,
   816  						)),
   817  						ghttp.RespondWithJSONEncoded(http.StatusTeapot, response),
   818  					),
   819  				)
   820  
   821  				err := client.ArtifactReferences.AddToRelease(productSlug, releaseID, artifactReferenceID)
   822  				Expect(err.Error()).To(ContainSubstring("foo message"))
   823  			})
   824  		})
   825  
   826  		Context("when the json unmarshalling fails with error", func() {
   827  			It("forwards the error", func() {
   828  				server.AppendHandlers(
   829  					ghttp.CombineHandlers(
   830  						ghttp.VerifyRequest("PATCH", fmt.Sprintf(
   831  							"%s/products/%s/releases/%d/add_artifact_reference",
   832  							apiPrefix,
   833  							productSlug,
   834  							releaseID,
   835  						)),
   836  						ghttp.RespondWith(http.StatusTeapot, "%%%"),
   837  					),
   838  				)
   839  
   840  				err := client.ArtifactReferences.AddToRelease(productSlug, releaseID, artifactReferenceID)
   841  				Expect(err).To(HaveOccurred())
   842  
   843  				Expect(err.Error()).To(ContainSubstring("invalid character"))
   844  			})
   845  		})
   846  	})
   847  
   848  	Describe("Remove Artifact Reference from release", func() {
   849  		var (
   850  			productSlug         = "some-product"
   851  			releaseID           = 2345
   852  			artifactReferenceID = 3456
   853  
   854  			expectedRequestBody = `{"artifact_reference":{"id":3456}}`
   855  		)
   856  
   857  		Context("when the server responds with a 204 status code", func() {
   858  			It("returns without error", func() {
   859  				server.AppendHandlers(
   860  					ghttp.CombineHandlers(
   861  						ghttp.VerifyRequest("PATCH", fmt.Sprintf(
   862  							"%s/products/%s/releases/%d/remove_artifact_reference",
   863  							apiPrefix,
   864  							productSlug,
   865  							releaseID,
   866  						)),
   867  						ghttp.VerifyJSON(expectedRequestBody),
   868  						ghttp.RespondWith(http.StatusNoContent, nil),
   869  					),
   870  				)
   871  
   872  				err := client.ArtifactReferences.RemoveFromRelease(productSlug, releaseID, artifactReferenceID)
   873  				Expect(err).NotTo(HaveOccurred())
   874  			})
   875  		})
   876  
   877  		Context("when the server responds with a non-204 status code", func() {
   878  			var (
   879  				response interface{}
   880  			)
   881  
   882  			BeforeEach(func() {
   883  				response = pivnetErr{Message: "foo message"}
   884  			})
   885  
   886  			It("returns an error", func() {
   887  				server.AppendHandlers(
   888  					ghttp.CombineHandlers(
   889  						ghttp.VerifyRequest("PATCH", fmt.Sprintf(
   890  							"%s/products/%s/releases/%d/remove_artifact_reference",
   891  							apiPrefix,
   892  							productSlug,
   893  							releaseID,
   894  						)),
   895  						ghttp.RespondWithJSONEncoded(http.StatusTeapot, response),
   896  					),
   897  				)
   898  
   899  				err := client.ArtifactReferences.RemoveFromRelease(productSlug, releaseID, artifactReferenceID)
   900  				Expect(err.Error()).To(ContainSubstring("foo message"))
   901  			})
   902  		})
   903  
   904  		Context("when the json unmarshalling fails with error", func() {
   905  			It("forwards the error", func() {
   906  				server.AppendHandlers(
   907  					ghttp.CombineHandlers(
   908  						ghttp.VerifyRequest("PATCH", fmt.Sprintf(
   909  							"%s/products/%s/releases/%d/remove_artifact_reference",
   910  							apiPrefix,
   911  							productSlug,
   912  							releaseID,
   913  						)),
   914  						ghttp.RespondWith(http.StatusTeapot, "%%%"),
   915  					),
   916  				)
   917  
   918  				err := client.ArtifactReferences.RemoveFromRelease(productSlug, releaseID, artifactReferenceID)
   919  				Expect(err).To(HaveOccurred())
   920  
   921  				Expect(err.Error()).To(ContainSubstring("invalid character"))
   922  			})
   923  		})
   924  	})
   925  })