Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ source-score
**coverage/
coverage.out
test_database.db
.amazonq/

# ide
.vscode/
Expand Down
128 changes: 128 additions & 0 deletions acceptance/source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,44 @@ var _ = Describe("Source model tests", func() {
})
})

When("POST request is sent with domainUrlNewsData field provided", func() {
It("should create source with domainUrlNewsData value", func() {
domainUrlNewsData := "example.com"
sourceInputWithDomain := api.SourceInput{
Name: "Source with Domain",
Summary: "Source with domainUrlNewsData field",
Tags: "domain-test",
Uri: "https://source-with-domain",
DomainUrlNewsData: &domainUrlNewsData,
}
body, err := json.Marshal(sourceInputWithDomain)
Expect(err).To(BeNil())

resp, err := doRequest(http.MethodPost, endpoint, body)
Expect(err).To(BeNil())
Expect(resp.StatusCode).To(BeEquivalentTo(http.StatusCreated))

var respBody api.CreateSourceResponse
err = json.NewDecoder(resp.Body).Decode(&respBody)
Expect(err).To(BeNil())
resp.Body.Close()

By("verifying source was created with domainUrlNewsData")
srcUrl, err := url.JoinPath(endpoint, respBody.UriDigest)
Expect(err).To(BeNil())
resp, err = doRequest(http.MethodGet, srcUrl, nil)
Expect(err).To(BeNil())
defer resp.Body.Close()
Expect(resp.StatusCode).To(Equal(http.StatusOK))

var source api.Source
err = json.NewDecoder(resp.Body).Decode(&source)
Expect(err).To(BeNil())
Expect(source.DomainUrlNewsData).To(Equal(domainUrlNewsData))
Expect(source.Name).To(Equal("Source with Domain"))
})
})

When("GET request is sent to query the created source", func() {
It("should return the created source", func() {
srcUrl, err := url.JoinPath(endpoint, uriDigest1)
Expand Down Expand Up @@ -154,6 +192,42 @@ var _ = Describe("Source model tests", func() {
})
})

When("PATCH request is sent to update domainUrlNewsData field", func() {
It("should update the source's domainUrlNewsData value", func() {
updatedDomainUrlNewsData := "updated-domain.com"
updatedSrcInput := api.SourcePatchInput{
DomainUrlNewsData: &updatedDomainUrlNewsData,
}
reqBody, err := json.Marshal(updatedSrcInput)
Expect(err).To(BeNil())

srcUrl, err := url.JoinPath(endpoint, uriDigest2)
Expect(err).To(BeNil())
req, err := http.NewRequest(http.MethodPatch, srcUrl, bytes.NewBuffer(reqBody))
Expect(err).To(BeNil())
addCommonHeaders(req)
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
Expect(err).To(BeNil())
Expect(resp.StatusCode).To(Equal(http.StatusNoContent))
resp.Body.Close()

By("verifying domainUrlNewsData got updated")
var src api.Source
resp, err = doRequest(http.MethodGet, srcUrl, nil)
Expect(err).To(BeNil())
defer resp.Body.Close()
Expect(resp.StatusCode).To(Equal(http.StatusOK))

err = json.NewDecoder(resp.Body).Decode(&src)
Expect(err).To(BeNil())
Expect(src.DomainUrlNewsData).To(Equal(updatedDomainUrlNewsData))
Expect(src.Name).To(Equal("Sample Source 2"))
Expect(src.Summary).To(Equal("Sample summary 2"))
Expect(src.Tags).To(Equal("tag2"))
})
})

When("DELETE request is sent to delete the created source", func() {
It("should delete the created source", func() {
srcUrl, err := url.JoinPath(endpoint, uriDigest1)
Expand Down Expand Up @@ -690,5 +764,59 @@ var _ = Describe("Source model tests", func() {
})
})

When("POST request with whitespace in domainUrlNewsData field value is sent", func() {
It("should return 400 Bad Request with nospace validation error message", func() {
domainUrlNewsDataWithSpace := "example com"
invalidInput := api.SourceInput{
Name: "Valid Name",
Summary: "Valid Summary",
Tags: "tag1,tag2",
Uri: "https://example.com",
DomainUrlNewsData: &domainUrlNewsDataWithSpace,
}
body, _ := json.Marshal(invalidInput)
resp, err := doRequest(http.MethodPost, endpoint, body)
Expect(err).To(BeNil())
defer resp.Body.Close()
Expect(resp.StatusCode).To(Equal(http.StatusBadRequest))

var errResp map[string]any
err = json.NewDecoder(resp.Body).Decode(&errResp)
Expect(err).To(BeNil())
Expect(errResp["error"]).ToNot(BeNil())
errorMsg := strings.ToLower(errResp["error"].(string))
Expect(errorMsg).To(ContainSubstring("domainurlnewsdata validation failed"))
Expect(errorMsg).To(ContainSubstring("nospace"))
})
})

When("PATCH request with empty string in domainUrlNewsData field value is sent", func() {
It("should return 400 Bad Request with nonempty validation error message", func() {
emptyDomainUrlNewsData := ""
invalidInput := api.SourcePatchInput{
DomainUrlNewsData: &emptyDomainUrlNewsData,
}
body, _ := json.Marshal(invalidInput)
srcUrl, err := url.JoinPath(endpoint, uriDigest2)
Expect(err).To(BeNil())
req, err := http.NewRequest(http.MethodPatch, srcUrl, bytes.NewBuffer(body))
Expect(err).To(BeNil())
addCommonHeaders(req)
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
Expect(err).To(BeNil())
defer resp.Body.Close()
Expect(resp.StatusCode).To(Equal(http.StatusBadRequest))

var errResp map[string]any
err = json.NewDecoder(resp.Body).Decode(&errResp)
Expect(err).To(BeNil())
Expect(errResp["error"]).ToNot(BeNil())
errorMsg := strings.ToLower(errResp["error"].(string))
Expect(errorMsg).To(ContainSubstring("domainurlnewsdata validation failed"))
Expect(errorMsg).To(ContainSubstring("nonempty"))
})
})

})
})
19 changes: 19 additions & 0 deletions api/source-score.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,12 @@ components:
x-oapi-codegen-extra-tags:
validate: httpsurl
binding: required
domainUrlNewsData:
type: string
description: Domain url corresponding to newsdata.io `domainurl` parameter
example: "timesofindia.indiatimes.com,theguardian.com"
x-oapi-codegen-extra-tags:
validate: omitnil,nonempty,nospace

SourcePatchInput:
type: object
Expand All @@ -512,6 +518,12 @@ components:
example: "news,journalism,trusted"
x-oapi-codegen-extra-tags:
validate: omitnil,nospace,nonempty
domainUrlNewsData:
type: string
description: Domain url corresponding to newsdata.io `domainurl` parameter
example: "timesofindia.indiatimes.com,theguardian.com"
x-oapi-codegen-extra-tags:
validate: omitnil,nonempty,nospace

Source:
type: object
Expand All @@ -523,6 +535,7 @@ components:
- tags
- uri
- uriDigest
- domainUrlNewsData
properties:
name:
type: string
Expand Down Expand Up @@ -562,6 +575,12 @@ components:
example: "https://www.nytimes.com"
x-oapi-codegen-extra-tags:
binding: required
domainUrlNewsData:
type: string
description: Domain url corresponding to newsdata.io `domainurl` parameter
example: "timesofindia.indiatimes.com,theguardian.com"
x-oapi-codegen-extra-tags:
binding: required

CreateSourceResponse:
type: object
Expand Down
9 changes: 9 additions & 0 deletions pkg/api/server.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions pkg/domain/source/source_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ func (sr *sourceRepository) PostSource(ctx context.Context, sourceInput *api.Sou
UriDigest: uriDigest,
}

if sourceInput.DomainUrlNewsData != nil {
source.DomainUrlNewsData = *sourceInput.DomainUrlNewsData
}

result := sr.client.Create(ctx, source)
slog.InfoContext(
ctx,
Expand Down Expand Up @@ -113,6 +117,9 @@ func (sr *sourceRepository) PatchSourceByUriDigest(ctx context.Context, sourceIn
if sourceInput.Tags != nil {
source.Tags = *sourceInput.Tags
}
if sourceInput.DomainUrlNewsData != nil {
source.DomainUrlNewsData = *sourceInput.DomainUrlNewsData
}

result = sr.client.Update(ctx, source)
slog.InfoContext(
Expand Down
3 changes: 3 additions & 0 deletions pkg/domain/source/source_repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,12 @@ var _ = Describe("Source model repository layer unit tests", Ordered, func() {
name := "Updated Sample Source 1"
summary := "Updated Sample summary"
tags := "updated-tag1"
domainUrlNewsData := "source1.com"
sourceInput := &api.SourcePatchInput{
Name: &name,
Summary: &summary,
Tags: &tags,
DomainUrlNewsData: &domainUrlNewsData,
}

err := sourceRepo.PatchSourceByUriDigest(context.TODO(), sourceInput, uriDigest1)
Expand All @@ -70,6 +72,7 @@ var _ = Describe("Source model repository layer unit tests", Ordered, func() {
Expect(source.Tags).To(BeEquivalentTo(*sourceInput.Tags))
Expect(source.Uri).To(BeEquivalentTo(sampleSourceInput1.Uri))
Expect(source.UriDigest).To(BeEquivalentTo(uriDigest1))
Expect(source.DomainUrlNewsData).To(BeEquivalentTo(domainUrlNewsData))
})
})

Expand Down
42 changes: 39 additions & 3 deletions pkg/domain/source/source_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,18 @@ var _ = Describe("Source model service layer unit test", Ordered, func() {
name := "Updated Sample Source 1"
summary := "Updated Sample summary"
tags := "updated-tag1"
domainUrlNewsData := "source1.com"
sourceInput := &api.SourcePatchInput{
Name: &name,
Summary: &summary,
Tags: &tags,
Name: &name,
Summary: &summary,
Tags: &tags,
DomainUrlNewsData: &domainUrlNewsData,
}
updatedSource = sampleSource1
updatedSource.Name = "Updated Sample Source 1"
updatedSource.Summary = "Updated Sample summary"
updatedSource.Tags = "updated-tag1"
updatedSource.DomainUrlNewsData = domainUrlNewsData
fakeSourceRepo.GetSourceByUriDigestReturnsOnCall(1, &updatedSource, nil)

err := sourceSvc.PatchSourceByUriDigest(context.TODO(), sourceInput, uriDigest1)
Expand All @@ -83,6 +86,7 @@ var _ = Describe("Source model service layer unit test", Ordered, func() {
Expect(source.Tags).To(BeEquivalentTo(*sourceInput.Tags))
Expect(source.Uri).To(BeEquivalentTo(sampleSourceInput1.Uri))
Expect(source.UriDigest).To(BeEquivalentTo(uriDigest1))
Expect(source.DomainUrlNewsData).To(BeEquivalentTo(domainUrlNewsData))
})
})

Expand Down Expand Up @@ -300,6 +304,38 @@ var _ = Describe("Source model service layer unit test", Ordered, func() {
Expect(strings.ToLower(err.Error())).To(ContainSubstring("nonempty"))
})
})

When("Patching a source's DomainUrlNewsData field with empty string value", func() {
It("Should return invalid source error with nonempty validation message", func() {
emptyDomainUrlNewsData := ""
invalidInput := &api.SourcePatchInput{
DomainUrlNewsData: &emptyDomainUrlNewsData,
}

err := sourceSvc.PatchSourceByUriDigest(context.TODO(), invalidInput, uriDigest1)

Expect(err).ToNot(BeNil())
Expect(errors.Is(err, apperrors.ErrInvalidSource)).To(BeTrue())
Expect(strings.ToLower(err.Error())).To(ContainSubstring("domainurlnewsdata validation failed"))
Expect(strings.ToLower(err.Error())).To(ContainSubstring("nonempty"))
})
})

When("Patching a source's DomainUrlNewsData field with a string containing spaces", func() {
It("Should return invalid source error with nospace validation message", func() {
domainUrlNewsDataWithSpaces := "example com"
invalidInput := &api.SourcePatchInput{
DomainUrlNewsData: &domainUrlNewsDataWithSpaces,
}

err := sourceSvc.PatchSourceByUriDigest(context.TODO(), invalidInput, uriDigest1)

Expect(err).ToNot(BeNil())
Expect(errors.Is(err, apperrors.ErrInvalidSource)).To(BeTrue())
Expect(strings.ToLower(err.Error())).To(ContainSubstring("domainurlnewsdata validation failed"))
Expect(strings.ToLower(err.Error())).To(ContainSubstring("nospace"))
})
})
})

Context("Source GET validation tests", func() {
Expand Down
Loading