Skip to content

[metadata manager m8s] Adding unit testcase for ListMetadata Rest API #1397

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

Open
wants to merge 12 commits into
base: metadata-management
Choose a base branch
from
Open
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
4 changes: 2 additions & 2 deletions api/pkg/metadata/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,15 @@ func (s *APIService) ListMetadata(request *restful.Request, response *restful.Re
listMetadataRequest, err := GetListMetaDataRequest(request)

if err != nil {
log.Errorf("Failed to construct list metadata request err: \n", err)
log.Errorf("Failed to construct list metadata request err: %v\n", err)
response.WriteEntity("Invalid type for sizeOfObject or sizeOfBucket request params. It should be integer type.")
return
}

//* calling the ListMetaData method from metadata manager m8s
res, err := s.metaClient.ListMetadata(ctx, &listMetadataRequest)
if err != nil {
log.Errorf("Failed to get metadata details err: \n", err)
log.Errorf("Failed to get metadata details err: %v\n", err)
response.WriteEntity(err)
return
}
Expand Down
80 changes: 80 additions & 0 deletions api/pkg/metadata/service_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* // Copyright 2023 The SODA Authors.
* //
* // Licensed under the Apache License, Version 2.0 (the "License");
* // you may not use this file except in compliance with the License.
* // You may obtain a copy of the License at
* //
* // http://www.apache.org/licenses/LICENSE-2.0
* //
* // Unless required by applicable law or agreed to in writing, software
* // distributed under the License is distributed on an "AS IS" BASIS,
* // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* // See the License for the specific language governing permissions and
* // limitations under the License.
*
*/

package metadata

import (
"github.com/emicklei/go-restful"
mt "github.com/opensds/multi-cloud/metadata/proto"
"github.com/stretchr/testify/assert"
"net/http"
"net/url"
"strconv"
"testing"
)

func GetRequest(uri string, param url.Values, t *testing.T) *restful.Request {
httpReq, err := http.NewRequest("GET", uri+param.Encode(), nil)
if err != nil {
t.Fail()
}
req := restful.NewRequest(httpReq)
return req
}

func Test_ListMetaData_Api_Param_Fetching(t *testing.T) {

validParams := make(url.Values)
validParams["limit"] = []string{"100"}
validParams["offset"] = []string{"1"}

invalidParams := make(url.Values)
invalidParams["limit"] = []string{"invalid"}
invalidParams["offset"] = []string{"1"}

tests := []struct {
title string
input interface{}
expectedOutput interface{}
expectedErr error
}{
{
title: "UT to test whether the request params are read correctly for valid values",
input: validParams,
expectedOutput: mt.ListMetadataRequest{Limit: 100, Offset: 1},
expectedErr: nil,
},
{
title: "UT to test whether the request params is giving error for invalid values",
input: invalidParams,
expectedOutput: nil,
expectedErr: &strconv.NumError{},
},
}

for _, test := range tests {
uri := "http://localhost:41651/v1/metadata/metadata/?"
values := test.input.(url.Values)
req := GetRequest(uri, values, t)
res, err := GetListMetaDataRequest(req)
if err != nil {
assert.NotNil(t, test.expectedErr, test.title)
} else {
assert.Equal(t, test.expectedOutput, res, test.title)
}
}
}
92 changes: 92 additions & 0 deletions metadata/pkg/query-manager/paginator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* // Copyright 2023 The SODA Authors.
* //
* // Licensed under the Apache License, Version 2.0 (the "License");
* // you may not use this file except in compliance with the License.
* // You may obtain a copy of the License at
* //
* // http://www.apache.org/licenses/LICENSE-2.0
* //
* // Unless required by applicable law or agreed to in writing, software
* // distributed under the License is distributed on an "AS IS" BASIS,
* // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* // See the License for the specific language governing permissions and
* // limitations under the License.
*
*/

package query_manager

import (
"github.com/opensds/multi-cloud/metadata/pkg/model"
"testing"
)

func TestPaginate(t *testing.T) {
tests := []struct {
unPaginatedResult []*model.MetaBackend
limit int32
offset int32
expectedResult []*model.MetaBackend
}{
{
unPaginatedResult: []*model.MetaBackend{
{Id: "1"},
{Id: "2"},
{Id: "3"},
{Id: "4"},
{Id: "5"},
},
limit: 2,
offset: 0,
expectedResult: []*model.MetaBackend{
{Id: "1"},
{Id: "2"},
},
},
{
unPaginatedResult: []*model.MetaBackend{
{Id: "1"},
{Id: "2"},
{Id: "3"},
{Id: "4"},
{Id: "5"},
},
limit: 2,
offset: 2,
expectedResult: []*model.MetaBackend{
{Id: "3"},
{Id: "4"},
},
},
{
unPaginatedResult: []*model.MetaBackend{
{Id: "1"},
{Id: "2"},
{Id: "3"},
{Id: "4"},
{Id: "5"},
},
limit: 2,
offset: 5,
expectedResult: []*model.MetaBackend{},
},
{
unPaginatedResult: []*model.MetaBackend{},
limit: 2,
offset: 0,
expectedResult: []*model.MetaBackend{},
},
}
for i, test := range tests {
result := Paginate(test.unPaginatedResult, test.limit, test.offset)
if len(result) != len(test.expectedResult) {
t.Errorf("Test case %d: expected length of result to be %d but got %d", i, len(test.expectedResult), len(result))
}
for j, r := range result {
if r.Id != test.expectedResult[j].Id {
t.Errorf("Test case %d: expected result at index %d to be %s but got %s", i, j, test.expectedResult[j].Id, r.Id)
}
}
}
}
175 changes: 175 additions & 0 deletions metadata/pkg/query-manager/translator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/*
* // Copyright 2023 The SODA Authors.
* //
* // Licensed under the Apache License, Version 2.0 (the "License");
* // you may not use this file except in compliance with the License.
* // You may obtain a copy of the License at
* //
* // http://www.apache.org/licenses/LICENSE-2.0
* //
* // Unless required by applicable law or agreed to in writing, software
* // distributed under the License is distributed on an "AS IS" BASIS,
* // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* // See the License for the specific language governing permissions and
* // limitations under the License.
*
*/

package query_manager

import (
pb "github.com/opensds/multi-cloud/metadata/proto"
"github.com/stretchr/testify/assert"
"go.mongodb.org/mongo-driver/bson"
"testing"
)

func Test_Translator(t *testing.T) {
sortAscBasedOnBackName := bson.D{{"$sort", bson.D{{"backendName", 1}}}}

backendNameMatch := bson.D{
bson.E{Key: "$match", Value: bson.D{
bson.E{Key: "backendName", Value: "backendName"}}}}

bucketNameMatch := bson.D{
bson.E{Key: "$match", Value: bson.D{
bson.E{Key: "buckets", Value: bson.D{
bson.E{Key: "$elemMatch", Value: bson.D{
bson.E{Key: "name", Value: bson.D{
bson.E{Key: "$eq", Value: "bucketName"}}}}}}}}}}

bucketNameFilter := bson.D{
bson.E{Key: "$project", Value: bson.D{
bson.E{Key: "_id", Value: 1},
bson.E{Key: "backendName", Value: 1},
bson.E{Key: "region", Value: 1},
bson.E{Key: "type", Value: 1},
bson.E{Key: "buckets", Value: bson.D{
bson.E{Key: "$filter", Value: bson.D{
bson.E{Key: "input", Value: "$buckets"},
bson.E{Key: "as", Value: "bucket"},
bson.E{Key: "cond", Value: bson.D{
bson.E{Key: "$and", Value: bson.A{bson.D{
bson.E{Key: "$eq", Value: bson.A{"$$bucket.name", "bucketName"}}}}}}}}}}},
bson.E{Key: "numberOfBuckets", Value: 1},
bson.E{Key: "numberOFilteredBuckets", Value: bson.D{
bson.E{Key: "$size", Value: bson.D{
bson.E{Key: "$filter", Value: bson.D{
bson.E{Key: "input", Value: "$buckets"},
bson.E{Key: "as", Value: "bucket"},
bson.E{Key: "cond",
Value: bson.D{
bson.E{Key: "$and",
Value: bson.A{bson.D{
bson.E{Key: "$eq", Value: bson.A{"$$bucket.name", "bucketName"}}}}}}}}}}}}}}}}

objectNameMatch := bson.D{
bson.E{Key: "$match", Value: bson.D{
bson.E{Key: "buckets", Value: bson.D{
bson.E{Key: "$elemMatch", Value: bson.D{
bson.E{Key: "objects.name", Value: bson.D{
bson.E{Key: "$eq", Value: "objectName"}}}}}}}}}}

objectNameFilter := bson.D{
bson.E{Key: "$project", Value: bson.D{
bson.E{Key: "_id", Value: 1},
bson.E{Key: "backendName", Value: 1},
bson.E{Key: "region", Value: 1},
bson.E{Key: "type", Value: 1},
bson.E{Key: "numberOfBuckets", Value: 1},
bson.E{Key: "buckets",
Value: bson.D{
bson.E{Key: "$map", Value: bson.D{
bson.E{Key: "input", Value: "$buckets"},
bson.E{Key: "as", Value: "bucket"},
bson.E{Key: "in", Value: bson.D{
bson.E{Key: "creationDate", Value: "$$bucket.creationDate"},
bson.E{Key: "name", Value: "$$bucket.name"},
bson.E{Key: "region", Value: "$$bucket.region"},
bson.E{Key: "type", Value: "$$bucket.type"},
bson.E{Key: "access", Value: "$$bucket.access"},
bson.E{Key: "numberOfObjects", Value: "$$bucket.numberOfObjects"},
bson.E{Key: "numberOfFilteredObjects", Value: bson.D{
bson.E{Key: "$size", Value: bson.D{
bson.E{Key: "$filter", Value: bson.D{
bson.E{Key: "input", Value: "$$bucket.objects"},
bson.E{Key: "as", Value: "object"},
bson.E{Key: "cond", Value: bson.D{
bson.E{Key: "$and", Value: bson.A{bson.D{
bson.E{Key: "$eq", Value: bson.A{"$$object.name", "objectName"}}}}}}}}}}}}},
bson.E{Key: "totalSize", Value: "$$bucket.totalSize"},
bson.E{Key: "filteredBucketSize", Value: bson.D{
bson.E{Key: "$sum", Value: bson.D{
bson.E{Key: "$map", Value: bson.D{
bson.E{Key: "input", Value: bson.D{
bson.E{Key: "$filter", Value: bson.D{
bson.E{Key: "input", Value: "$$bucket.objects"},
bson.E{Key: "as", Value: "object"},
bson.E{Key: "cond", Value: bson.D{
bson.E{Key: "$and", Value: bson.A{bson.D{
bson.E{Key: "$eq", Value: bson.A{"$$object.name", "objectName"}}}}}}}}}}},
bson.E{Key: "as", Value: "object"},
bson.E{Key: "in", Value: "$$object.size"}}}}}}},
bson.E{Key: "tags", Value: "$$bucket.tags"},
bson.E{Key: "objects", Value: bson.D{
bson.E{Key: "$filter", Value: bson.D{
bson.E{Key: "input", Value: "$$bucket.objects"},
bson.E{Key: "as", Value: "object"},
bson.E{Key: "cond", Value: bson.D{
bson.E{Key: "$and", Value: bson.A{bson.D{
bson.E{Key: "$eq", Value: bson.A{"$$object.name", "objectName"}}}}}}}}}}}}}}}}}}}}
removeEmptyBucketsFilter := bson.D{
bson.E{Key: "$project", Value: bson.D{
bson.E{Key: "_id", Value: 1},
bson.E{Key: "backendName", Value: 1},
bson.E{Key: "region", Value: 1},
bson.E{Key: "type", Value: 1},
bson.E{Key: "buckets", Value: bson.D{
bson.E{Key: "$filter", Value: bson.D{
bson.E{Key: "input", Value: "$buckets"},
bson.E{Key: "as", Value: "bucket"},
bson.E{Key: "cond", Value: bson.D{
bson.E{Key: "$and", Value: bson.A{bson.D{
bson.E{Key: "$ifNull", Value: bson.A{"$$bucket.numberOfFilteredObjects", false}}}}}}}}}}},
bson.E{Key: "numberOfBuckets", Value: 1},
bson.E{Key: "numberOFilteredBuckets", Value: bson.D{
bson.E{Key: "$size", Value: bson.D{
bson.E{Key: "$filter", Value: bson.D{
bson.E{Key: "input", Value: "$buckets"},
bson.E{Key: "as", Value: "bucket"},
bson.E{Key: "cond", Value: bson.D{
bson.E{Key: "$and", Value: bson.A{bson.D{
bson.E{Key: "$ifNull", Value: bson.A{"$$bucket.numberOfFilteredObjects", false}}}}}}}}}}}}}}}}

tests := []struct {
title string
input pb.ListMetadataRequest
expectedOutput interface{}
}{
{
title: "Empty Request",
input: pb.ListMetadataRequest{},
expectedOutput: []bson.D{sortAscBasedOnBackName},
},
{
title: "Query Backend Name",
input: pb.ListMetadataRequest{BackendName: "backendName"},
expectedOutput: []bson.D{backendNameMatch, sortAscBasedOnBackName},
},
{
title: "Query Bucket Name",
input: pb.ListMetadataRequest{BucketName: "bucketName"},
expectedOutput: []bson.D{bucketNameMatch, bucketNameFilter, sortAscBasedOnBackName},
},
{
title: "Query Object Name",
input: pb.ListMetadataRequest{ObjectName: "objectName"},
expectedOutput: []bson.D{objectNameMatch, objectNameFilter, removeEmptyBucketsFilter, sortAscBasedOnBackName},
},
}

for _, test := range tests {
output := Translate(&test.input)
assert.Equal(t, test.expectedOutput, output, test.title)
}
}
Loading