Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🌱 add dependency package in test/api #375

Merged
merged 10 commits into from
Jun 9, 2023
51 changes: 51 additions & 0 deletions binding/dependency.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package binding

import (
"github.com/konveyor/tackle2-hub/api"
)

//
// Dependency API.
type Dependency struct {
// hub API client.
client *Client
}

//
// Create a Dependency.
func (h *Dependency) Create(r *api.Dependency) (err error) {
err = h.client.Post(api.DependenciesRoot, &r)
return
}

//
// Get a Dependency by ID.
func (h *Dependency) Get(id uint) (r *api.Dependency, err error) {
r = &api.Dependency{}
path := Path(api.DependencyRoot).Inject(Params{api.ID: id})
err = h.client.Get(path, r)
return
}

//
// List Dependencies.
func (h *Dependency) List() (list []api.Dependency, err error) {
list = []api.Dependency{}
err = h.client.Get(api.DependenciesRoot, &list)
return
}

//
// Update a Dependency.
func (h *Dependency) Update(r *api.Dependency) (err error) {
khareyash05 marked this conversation as resolved.
Show resolved Hide resolved
path := Path(api.DependencyRoot).Inject(Params{api.ID: r.From.ID})
err = h.client.Put(path, r)
return
}

//
// Delete a Dependency.
func (h *Dependency) Delete(id uint) (err error) {
err = h.client.Delete(Path(api.DependencyRoot).Inject(Params{api.ID: id}))
return
}
6 changes: 5 additions & 1 deletion binding/richclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func init() {
type RichClient struct {
// Resources APIs.
Application Application
Bucket Bucket
Bucket Bucket
BusinessService BusinessService
Identity Identity
JobFunction JobFunction
Expand All @@ -32,6 +32,7 @@ type RichClient struct {
Tag Tag
TagCategory TagCategory
Task Task
Dependency Dependency

// A REST client.
client *Client
Expand Down Expand Up @@ -60,6 +61,9 @@ func New(baseUrl string) (r *RichClient) {
BusinessService: BusinessService{
client: client,
},
Dependency: Dependency{
client: client,
},
Identity: Identity{
client: client,
},
Expand Down
76 changes: 76 additions & 0 deletions test/api/dependency/api_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package dependency

import (
"testing"

"github.com/konveyor/tackle2-hub/test/assert"
)

func TestDependencyCRUD(t *testing.T) {
for _, r := range Samples {
t.Run("Dependency_CRUD", func(t *testing.T) {
khareyash05 marked this conversation as resolved.
Show resolved Hide resolved
// Create.
err := Dependency.Create(&r)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API Dependency links two Applications and keeps their IDs in From/To fields. These fields are Refs (https://github.com/konveyor/tackle2-hub/blob/main/api/base.go#L379) so contain just IDs (and optionally Name, not that not important), but the Refs are not actual Applications. The From and To Applications need to be created before creating Dependency.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I understood from the review that dependency need To/From fields which will be used to refer to the applications?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and that To/From will be generated by creating an instance of application in api_test.go. Am i in the right direction?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

if err != nil {
khareyash05 marked this conversation as resolved.
Show resolved Hide resolved
t.Errorf(err.Error())
}

// Get.
got, err := Dependency.Get(r.ID)
if err != nil {
t.Errorf(err.Error())
}
if assert.FlatEqual(got, r) {
t.Errorf("Different response error. Got %v, expected %v", got, r)
}

// Update.
r.Name = "Updated " + r.Name
err = Dependency.Update(&r)
if err != nil {
t.Errorf(err.Error())
}

got, err = Dependency.Get(r.ID)
if err != nil {
t.Errorf(err.Error())
}
if got.Name != r.Name {
t.Errorf("Different response error. Got %s, expected %s", got.Name, r.Name)
}

// Delete.
err = Dependency.Delete(r.ID)
if err != nil {
t.Errorf(err.Error())
}

_, err = Dependency.Get(r.ID)
if err == nil {
t.Errorf("Resource exits, but should be deleted: %v", r)
}
})
}
}

func TestDependencyList(t *testing.T) {
samples := Samples

for name := range samples {
sample := samples[name]
assert.Must(t, Dependency.Create(&sample))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same with creating Dependencies - 1st Applications, 2nd Dependency between them.

samples[name] = sample
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a Dependency creation and condition below should check if got is an array with the created dependency. Sorry, I missed this part before.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall I just compare the ID's of dependency created and the ApplicationFrom/To ID's will it suffice?

got, err := Dependency.List()
if err != nil {
t.Errorf(err.Error())
}
if assert.FlatEqual(got, &samples) {
t.Errorf("Different response error. Got %v, expected %v", got, samples)
}

for _, r := range samples {
assert.Must(t, Dependency.Delete(r.ID))
}
}
19 changes: 19 additions & 0 deletions test/api/dependency/pkg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package dependency

import (
"github.com/konveyor/tackle2-hub/binding"
"github.com/konveyor/tackle2-hub/test/api/client"
)

var (
RichClient *binding.RichClient
Dependency binding.Dependency
)

func init() {
// Prepare RichClient and login to Hub API (configured from env variables).
RichClient = client.PrepareRichClient()

// Shortcut for Dependencyrelated RichClient methods.
Dependency = RichClient.Dependency
khareyash05 marked this conversation as resolved.
Show resolved Hide resolved
}
44 changes: 44 additions & 0 deletions test/api/dependency/samples.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package dependency

import (
"github.com/konveyor/tackle2-hub/api"
)

// Set of valid resources for tests and reuse.
type TestCase struct {
Name string
Dependency api.Dependency
Application1 api.Application
Application2 api.Application
}

var (
dependency = api.Dependency{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of these lines seems to be redundant to me (the dependency here and init() below). But I'd suggest get it to (partially) working state (passing tests against locally running Hub https://github.com/konveyor/tackle2-hub/tree/main/test#rest-api) and we can refactor it then.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored the code Kindly review

To: api.Ref{
ID: uint(1),
khareyash05 marked this conversation as resolved.
Show resolved Hide resolved
Name: "Alice",
},
From: api.Ref{
ID: uint(2),
Name: "Bob",
},
}

aliceApplication = api.Application{
Name: "Alice",
Description: "alice's application",
khareyash05 marked this conversation as resolved.
Show resolved Hide resolved
}
bobApplication = api.Application{
Name: "Bob",
Description: "bob's application",
}

testCase = TestCase{
Name: "Test",
Dependency: dependency,
Application1: aliceApplication,
Application2: bobApplication,
}
tc = []TestCase{testCase}
Samples = []api.Dependency{tc}
)
Copy link
Member

@aufi aufi Jun 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definition of Dependencies (and likely also TestCases) will need to be updated. There is some limitation caused by api.Dependency keeping just Ref of Aplication, so we need store application elsewhere. I can see few options:

  • Use TestCases struct that might even not contain the Dependency itself, but something like just ApplicationFrom and ApplicationTo, so the test will go through testcases and create ApplicationTo, ApplicationFrom and then dependency between these applications (the dependency doesn't have any special fields than the Application refs, so it should work well).
  • Use model.Dependency model, that stores links to Application (not just Refs), see https://github.com/konveyor/tackle2-hub/blob/main/migration/v2/model/dependency.go#L12-L18 (yes, we do have slightly different models for database and API). The Samples array would be array of these model.Dependency and test could create both Applications and "convert" the model.Dependency to api.Dependency using method With() https://github.com/konveyor/tackle2-hub/blob/main/api/dependency.go#L157-L161
  • It would great if you can try both ways (or maybe find something else if you'd like it more than suggestions above) and we can discuss how it works if needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definition of Dependencies (and likely also TestCases) will need to be updated. There is some limitation caused by api.Dependency keeping just Ref of Aplication, so we need store application elsewhere. I can see few options:

  • Use TestCases struct that might even not contain the Dependency itself, but something like just ApplicationFrom and ApplicationTo, so the test will go through testcases and create ApplicationTo, ApplicationFrom and then dependency between these applications (the dependency doesn't have any special fields than the Application refs, so it should work well).
  • Use model.Dependency model, that stores links to Application (not just Refs), see https://github.com/konveyor/tackle2-hub/blob/main/migration/v2/model/dependency.go#L12-L18 (yes, we do have slightly different models for database and API). The Samples array would be array of these model.Dependency and test could create both Applications and "convert" the model.Dependency to api.Dependency using method With() https://github.com/konveyor/tackle2-hub/blob/main/api/dependency.go#L157-L161
  • It would great if you can try both ways (or maybe find something else if you'd like it more than suggestions above) and we can discuss how it works if needed.

I think 1st option is easier to implement because it involves less complexities and 2nd option is is less intuitive which can be easily dealt by the 1st. What's your say on that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a thought process of injecting dependency withdependecy-less TestCase in Samples[]. and then use From/To in the api_test.go to access them in the dependency to be used by various CRUD functions.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I fully understand, but sounds good.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A Followup to this discussion and the 1st option, the dependency variable (and Samples containing only the dependency when api_test.go creates new applicationFrom/To instances) here seems to me to be overcomplicated.
What about drop the dependency variable, considering update/rename TestCase and putting to Samples (or renamed array for tests) and doing all this in since var( ... ) block?