Skip to content

Commit

Permalink
🌱 add csv import test (#390)
Browse files Browse the repository at this point in the history
Closes #388 

Work Done as of now
1. Created a sample of data to be passed in `samples.go`
2. Initialized RichClient.Client
3. Uploaded CSV using FilePost
4. Get contents of `/importsummaries` 
5. Compare Applications and Dependencies with the output of the API
6. Compare valid count with no. of Applications and Dependencies
7. Added checks for all routes
8. Download the CSV
9. Compare informations of CSV's

---------

Signed-off-by: Yash Khare <[email protected]>
  • Loading branch information
khareyash05 authored Jul 3, 2023
1 parent 65bae5e commit f8f1e0d
Show file tree
Hide file tree
Showing 6 changed files with 366 additions and 3 deletions.
26 changes: 24 additions & 2 deletions binding/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
pathlib "path"
"path/filepath"
"strings"
"time"
"time"
)

const (
Expand Down Expand Up @@ -192,7 +192,6 @@ func (r *Client) Post(path string, object interface{}) (err error) {
default:
err = liberr.New(http.StatusText(status))
}

return
}

Expand Down Expand Up @@ -447,6 +446,29 @@ func (r *Client) FilePut(path, source string, object interface{}) (err error) {
return
}

//
// FilePost uploads a file.
// Returns the created File resource.
func (r *Client) FilePost(path, source string, object interface{}) (err error) {
isDir, nErr := r.IsDir(source, true)
if nErr != nil {
err = nErr
return
}
if isDir {
err = liberr.New("Must be regular file.")
return
}
fields := []Field{
{
Name: api.FileField,
Path: source,
},
}
err = r.FileSend(path, http.MethodPost, fields, object)
return
}

//
// FileSend sends file upload from.
func (r *Client) FileSend(path, method string, fields []Field, object interface{}) (err error) {
Expand Down
2 changes: 1 addition & 1 deletion docs/test-api-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ application|:white_check_mark: partially|:heavy_check_mark:||
bucket||||partially within application
dependency|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
file|:heavy_check_mark:|:heavy_check_mark:||
import||||
import||:heavy_check_mark:||
review||||
**Controls**||||
businessservice|:heavy_check_mark:|:heavy_check_mark:||
Expand Down
171 changes: 171 additions & 0 deletions test/api/importcsv/api_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package importcsv

import (
"io/ioutil"
"os"
"testing"
"time"
"github.com/konveyor/tackle2-hub/api"
"github.com/konveyor/tackle2-hub/binding"
"github.com/konveyor/tackle2-hub/test/assert"
)

func TestImportCSV(t *testing.T) {
for _, r := range TestCases {
t.Run(r.FileName, func(t *testing.T) {

// Upload CSV.
inputData := api.ImportSummary{}
assert.Must(t, Client.FilePost(api.UploadRoot, r.FileName, &inputData))

// Inject import summary id into Summary root
pathForImportSummary := binding.Path(api.SummaryRoot).Inject(binding.Params{api.ID: inputData.ID})

// Since uploading the CSV happens asynchronously we need to wait for the upload to check Applications and Dependencies.
time.Sleep(time.Second)

var outputImportSummaries []api.ImportSummary
outputMatchingSummary := api.ImportSummary{}
for{
assert.Should(t, Client.Get(api.SummariesRoot, &outputImportSummaries))
for _, gotImport := range outputImportSummaries {
if uint(gotImport.ID) == inputData.ID {
outputMatchingSummary = gotImport
}
}
if(outputMatchingSummary.ValidCount + outputMatchingSummary.InvalidCount == len(r.ExpectedApplications)+len(r.ExpectedDependencies)){
break
}
time.Sleep(time.Second)
}

// Check list of Applications.
gotApps, _ := Application.List()
if len(gotApps) != len(r.ExpectedApplications) {
t.Errorf("Mismatch in number of imported Applications: Expected %d, Actual %d", len(r.ExpectedApplications), len(gotApps))
} else {
for i, gotApp := range gotApps {
if r.ExpectedApplications[i].Name != gotApp.Name {
t.Errorf("Mismatch in name of imported Application: Expected %s, Actual %s", r.ExpectedApplications[i].Name, gotApp.Name)
}
if r.ExpectedApplications[i].Description != gotApp.Description {
t.Errorf("Mismatch in description of imported Application: Expected %s, Actual %s", r.ExpectedApplications[i].Description, gotApp.Description)
}
if r.ExpectedApplications[i].Repository.Kind != gotApp.Repository.Kind {
t.Errorf("Mismatch in repository's kind ofimported Application: Expected %s, Actual %s", r.ExpectedApplications[i].Repository.Kind, gotApp.Repository.Kind)
}
if r.ExpectedApplications[i].Repository.URL != gotApp.Repository.URL {
t.Errorf("Mismatch in repository's url of imported Application: Expected %s, Actual %s", r.ExpectedApplications[i].Repository.URL, gotApp.Repository.URL)
}
if r.ExpectedApplications[i].Binary != gotApp.Binary {
t.Errorf("Mismatch in binary of imported Application: Expected %s, Actual %s", r.ExpectedApplications[i].Binary, gotApp.Binary)
}
for j, tag := range r.ExpectedApplications[i].Tags {
if tag.Name != gotApp.Tags[j].Name {
t.Errorf("Mismatch in tag name of imported Application: Expected %s, Actual %s", tag.Name, gotApp.Tags[j].Name)
}
}
if r.ExpectedApplications[i].BusinessService.Name != gotApp.BusinessService.Name {
t.Errorf("Mismatch in name of the BusinessService of imported Application: Expected %s, Actual %s", r.ExpectedApplications[i].BusinessService.Name, gotApp.BusinessService.Name)
}
}
}

// Check list of Dependencies.
gotDeps, _ := Dependency.List()
if len(gotDeps) != len(r.ExpectedDependencies) {
t.Errorf("Mismatch in number of imported Dependencies: Expected %d, Actual %d", len(r.ExpectedDependencies), len(gotDeps))
} else {
for i, importedDep := range gotDeps {
if importedDep.To.Name != r.ExpectedDependencies[i].To.Name {
t.Errorf("Mismatch in imported Dependency: Expected %s, Actual %s", r.ExpectedDependencies[i].To.Name, importedDep.To.Name)
}
if importedDep.From.Name != r.ExpectedDependencies[i].From.Name {
t.Errorf("Mismatch in imported Dependency: Expected %s, Actual %s", r.ExpectedDependencies[i].From.Name, importedDep.From.Name)
}
}
}

// Get summaries of the Input ID.
outputImportSummary := api.ImportSummary{}
assert.Should(t, Client.Get(pathForImportSummary, &outputImportSummary))

// Get all imports.
var outputImports []api.Import
assert.Should(t, Client.Get(api.ImportsRoot, &outputImports))

// Check for number of imports.
if len(outputImports) != len(r.ExpectedApplications)+len(r.ExpectedDependencies) {
t.Errorf("Mismatch in number of imports")
}

// Checks for individual applications and dependencies.
j, k := 0, 0
for _, imp := range outputImports {
if imp["recordType1"] == 1 && j < len(r.ExpectedApplications) {
// An Application with no dependencies.
if r.ExpectedApplications[j].Name != imp["applicationName"] {
t.Errorf("Mismatch in name of import: Expected %s, Actual %s", r.ExpectedApplications[j].Name, imp["applicationName"])
}
if r.ExpectedApplications[j].Description != imp["description"] {
t.Errorf("Mismatch in name of import: Expected %s, Actual %s", r.ExpectedApplications[j].Description, imp["description"])
}
if r.ExpectedApplications[j].BusinessService.Name != imp["businessService"] {
t.Errorf("Mismatch in name of import: Expected %s, Actual %s", r.ExpectedApplications[j].BusinessService.Name, imp["businessService"])
}
j++
}
if imp["recordType1"] == 2 && k < len(r.ExpectedDependencies) {
// An Application with Dependencies.
if r.ExpectedDependencies[k].From.Name != imp["applicationName"] {
t.Errorf("Mismatch in name of import: Expected %s, Actual %s", r.ExpectedDependencies[k].From.Name, imp["applicationName"])
}
if r.ExpectedDependencies[k].To.Name != imp["dependency"] {
t.Errorf("Mismatch in name of import: Expected %s, Actual %s", r.ExpectedDependencies[k].To.Name, imp["dependency"])
}
k++
}
}

// Download the csv.
pathToGotCSV := "downloadcsv.csv"
assert.Should(t, Client.FileGet(api.DownloadRoot, pathToGotCSV))

// Read the got CSV file.
gotCSV, err := ioutil.ReadFile(pathToGotCSV)
if err != nil {
t.Errorf("Error reading CSV: %s", pathToGotCSV)
}
gotCSVString := string(gotCSV)

// Read the expected CSV file.
expectedCSV, err := ioutil.ReadFile(r.FileName)
if err != nil {
t.Errorf("Error reading CSV: %s", r.FileName)
}
expectedCSVString := string(expectedCSV)
if gotCSVString != expectedCSVString {
t.Errorf("The CSV files have different content %s and %s", gotCSVString, expectedCSVString)
}

// Remove the CSV file created.
err = os.Remove(pathToGotCSV)
if err != nil {
t.Errorf(err.Error())
}

// Delete imported summaries
assert.Must(t, Client.Delete(pathForImportSummary))

// Delete imported Applications.
for _, apps := range gotApps {
assert.Must(t, Application.Delete(apps.ID))
}

// Delete imported Dependencies.
for _, deps := range gotDeps {
assert.Must(t, Dependency.Delete(deps.ID))
}
})
}
}
27 changes: 27 additions & 0 deletions test/api/importcsv/pkg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package importcsv

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

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

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

// Access REST client directly
Client = RichClient.Client

// Access Application directly
Application = RichClient.Application

// Access Dependency directly
Dependency = RichClient.Dependency
}
137 changes: 137 additions & 0 deletions test/api/importcsv/samples.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package importcsv

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

type TestCase struct {
FileName string
ExpectedApplications []api.Application
ExpectedDependencies []api.Dependency
}

var (
TestCases = []TestCase{
{
FileName: "template_application_import.csv",
ExpectedApplications: []api.Application{
{
Name: "Customers",
Description: "Legacy Customers management service",
Bucket: &api.Ref{},
Repository: &api.Repository{
Kind: "git",
URL: "https://git-acme.local/customers.git",
Branch: "",
Tag: "",
Path: "",
},
Binary: "corp.acme.demo:customers-tomcat:0.0.1-SNAPSHOT:war",
Tags: []api.TagRef{
{
Name: "Oracle",
Source: "",
},
{
Name: "Java",
Source: "",
},
{
Name: "RHEL 8",
Source: "",
},
{
Name: "Tomcat",
Source: "",
},
},
BusinessService: &api.Ref{
Name: "Retail",
},
},
{
Name: "Inventory",
Description: "Inventory service",
Bucket: &api.Ref{},
Repository: &api.Repository{
Kind: "git",
URL: "https://git-acme.local/inventory.git",
Branch: "",
Tag: "",
Path: "",
},
Binary: "corp.acme.demo:inventory:0.1.1-SNAPSHOT:war",
Tags: []api.TagRef{
{
Name: "PostgreSQL",
Source: "",
},
{
Name: "Java",
Source: "",
},
{
Name: "RHEL 8",
Source: "",
},
{
Name: "Quarkus",
Source: "",
},
},
BusinessService: &api.Ref{
Name: "Retail",
},
},
{
Name: "Gateway",
Description: "API Gateway",
Bucket: &api.Ref{},
Repository: &api.Repository{
Kind: "git",
URL: "https://git-acme.local/gateway.git",
Branch: "",
Tag: "",
Path: "",
},
Binary: "corp.acme.demo:gateway:0.1.1-SNAPSHOT:war",
Tags: []api.TagRef{
{
Name: "Java",
Source: "",
},
{
Name: "RHEL 8",
Source: "",
},
{
Name: "Spring Boot",
Source: "",
},
},
BusinessService: &api.Ref{
Name: "Retail",
},
},
},
ExpectedDependencies: []api.Dependency{
{
To: api.Ref{
Name: "Inventory",
},
From: api.Ref{
Name: "Gateway",
},
},
{
To: api.Ref{
Name: "Customers",
},
From: api.Ref{
Name: "Gateway",
},
},
},
},
}
)
Loading

0 comments on commit f8f1e0d

Please sign in to comment.