refactor
diff --git a/api.go b/api.go index cebd66b..2ad5103 100644 --- a/api.go +++ b/api.go
@@ -2,7 +2,6 @@ import ( "encoding/json" - "fmt" "github.com/30x/apid-core" "github.com/30x/apidQuota/constants" "github.com/30x/apidQuota/globalVariables" @@ -43,12 +42,11 @@ results, err := qBucket.IncrementQuotaLimit() if err != nil { - util.WriteErrorResponse(http.StatusBadRequest, constants.UnMarshalJSONError, "error retrieving count for the give identifier "+err.Error(), res, req) + util.WriteErrorResponse(http.StatusBadRequest, constants.ErrorCheckingQuotaLimit, "error retrieving count for the give identifier "+err.Error(), res, req) return } respMap := results.ToAPIResponse() - fmt.Println("results from inc quota: ", results) respbytes, err := json.Marshal(respMap) res.Header().Set("Content-Type", "application/json")
diff --git a/api_test.go b/api_test.go index 9d6452c..4bae205 100644 --- a/api_test.go +++ b/api_test.go
@@ -3,15 +3,96 @@ import ( . "github.com/onsi/ginkgo" //"net/http" + "encoding/json" + "net/http" + "io/ioutil" + "bytes" + "time" ) func init() { //testAPIDQuotaURL = "" } -var _ = Describe("Api", func() { - It("test Synchronous quota", func() { +var testhttpClient *http.Client = &http.Client{ + //setting the timeout to 60 sec for requests to counterService + Timeout: time.Duration(60 * time.Second), +} - //req, err := http.NewRequest("POST", ) +const testQuotaAPIURL = "http://localhost:9000/quota" + +var _ = Describe("Api Tests", func() { + FIt("test Synchronous quota - valid test cases", func() { + requestData := make(map[string]interface{}) + requestData["edgeOrgID"] = "testTenant" + requestData["id"] = "testID" + requestData["interval"] = 1 + requestData["timeUnit"] = "HOUR" + requestData["quotaType"] = "CALENDAR" + requestData["preciseAtSecondsLevel"] = false + requestData["startTime"] = 1489189921 + requestData["maxCount"] = 5 + requestData["bucketType"] = "Synchronous" + requestData["weight"] = 2 + + reqBytes, err := json.Marshal(requestData) + if err != nil { + Fail("error converting requestBody into bytes: " + err.Error()) + } + + //valid request body + req, err := http.NewRequest("POST", testQuotaAPIURL, ioutil.NopCloser(bytes.NewReader(reqBytes))) + if err != nil { + Fail("error getting newRequest: " + err.Error()) + } + + res, err := testhttpClient.Do(req) + if err != nil { + Fail("error calling the api: " + err.Error()) + } + + // Check the status code is what we expect. + if status := res.StatusCode; status != http.StatusOK { + Fail("wrong status code: " + res.Status) + } + + //valid request - case insensitive - timeUnit, quotaType, bucketType + requestData["timeUnit"] = "HoUR" + requestData["quotaType"] = "cALEndar" + requestData["bucketType"] = "syncHRonous" + + req, err = http.NewRequest("POST", testQuotaAPIURL, ioutil.NopCloser(bytes.NewReader(reqBytes))) + if err != nil { + Fail("error getting newRequest: " + err.Error()) + } + + res, err = testhttpClient.Do(req) + if err != nil { + Fail("error calling the api: " + err.Error()) + } + + // Check the status code is what we expect. + if status := res.StatusCode; status != http.StatusOK { + Fail("wrong status code: " + res.Status) + } + + //valid request - startTime not sent in request - optional. + delete(requestData, "startTime") + + req, err = http.NewRequest("POST", testQuotaAPIURL, ioutil.NopCloser(bytes.NewReader(reqBytes))) + if err != nil { + Fail("error getting newRequest: " + err.Error()) + } + + res, err = testhttpClient.Do(req) + if err != nil { + Fail("error calling the api: " + err.Error()) + } + + // Check the status code is what we expect. + if status := res.StatusCode; status != http.StatusOK { + Fail("wrong status code: " + res.Status) + } + }) })
diff --git a/constants/constants.go b/constants/constants.go index 9ced04b..261e9cb 100644 --- a/constants/constants.go +++ b/constants/constants.go
@@ -5,6 +5,7 @@ UnMarshalJSONError = "unmarshal_json_error" ErrorConvertReqBodyToEntity = "error_convert_reqBody_to_entity" ConfigQuotaBasePath = "quota_base_path" + ErrorCheckingQuotaLimit = "error_checking_quota_limit" QuotaBasePathDefault = "/quota" ConfigCounterServiceBasePath = "counterService_base_path"
diff --git a/quotaBucket/apiUtil.go b/quotaBucket/apiUtil.go index 5515271..30cffed 100644 --- a/quotaBucket/apiUtil.go +++ b/quotaBucket/apiUtil.go
@@ -3,14 +3,21 @@ import ( "errors" "reflect" + "time" +) + +const ( + reqEdgeOrgID = "edgeOrgID" + reqID = "id" + reqMaxCount = "maxCount" ) type QuotaBucketResults struct { EdgeOrgID string ID string - exceededTokens bool - allowedTokens int64 MaxCount int64 + exceededTokens bool + currentTokens int64 startedAt int64 expiresAt int64 } @@ -21,7 +28,7 @@ var startTime, maxCount, weight int64 var preciseAtSecondsLevel bool - value, ok := quotaBucketMap["edgeOrgID"] + value, ok := quotaBucketMap[reqEdgeOrgID] if !ok { return errors.New(`missing field: 'edgeOrgID' is required`) } @@ -30,7 +37,7 @@ } edgeOrgID = value.(string) - value, ok = quotaBucketMap["id"] + value, ok = quotaBucketMap[reqID] if !ok { return errors.New(`missing field: 'id' is required`) } @@ -80,8 +87,8 @@ preciseAtSecondsLevel = value.(bool) value, ok = quotaBucketMap["startTime"] - if !ok { - return errors.New(`missing field: 'startTime' is required`) + if !ok { //todo: in the current cps code startTime is optional for QuotaBucket. should we make start time optional to NewQuotaBucket? + startTime = time.Now().UTC().Unix() } //from input when its read its float, need to then convert to int. if startTimeType := reflect.TypeOf(value); startTimeType.Kind() != reflect.Float64 { @@ -90,7 +97,7 @@ startTimeFloat := value.(float64) startTime = int64(startTimeFloat) - value, ok = quotaBucketMap["maxCount"] + value, ok = quotaBucketMap[reqMaxCount] if !ok { return errors.New(`missing field: 'maxCount' is required`) } @@ -121,10 +128,9 @@ weightFloat := value.(float64) weight = int64(weightFloat) - newQBucket, err := NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, startTime, maxCount, bucketType, weight) if err != nil { - return errors.New("error creating newquotaBucket: " + err.Error()) + return errors.New("error creating quotaBucket: " + err.Error()) } @@ -138,16 +144,15 @@ } -func (qBucketResults *QuotaBucketResults) ToAPIResponse() (map[string]interface{}) { +func (qBucketResults *QuotaBucketResults) ToAPIResponse() map[string]interface{} { resultsMap := make(map[string]interface{}) - resultsMap["edgeOrgID"] = qBucketResults.ID - resultsMap["id"] = qBucketResults.ID + resultsMap[reqEdgeOrgID] = qBucketResults.ID + resultsMap[reqID] = qBucketResults.ID + resultsMap[reqMaxCount] = qBucketResults.MaxCount resultsMap["exceededTokens"] = qBucketResults.exceededTokens - resultsMap["allowedTokens"] = qBucketResults.allowedTokens - resultsMap["MaxCount"] = qBucketResults.MaxCount + resultsMap["currentTokens"] = qBucketResults.currentTokens resultsMap["startedAt"] = qBucketResults.startedAt resultsMap["expiresAt"] = qBucketResults.expiresAt - return resultsMap -} \ No newline at end of file +}
diff --git a/quotaBucket/quotaBucket.go b/quotaBucket/quotaBucket.go index c06247f..546ff10 100644 --- a/quotaBucket/quotaBucket.go +++ b/quotaBucket/quotaBucket.go
@@ -2,7 +2,6 @@ import ( "errors" - "fmt" "github.com/30x/apidQuota/services" "strings" "time" @@ -45,34 +44,45 @@ } -type QuotaPeriod struct { +type quotaPeriodData struct { inputStartTime time.Time startTime time.Time endTime time.Time } +type QuotaPeriod struct { + quotaPeriodData +} + func NewQuotaPeriod(inputStartTime int64, startTime int64, endTime int64) QuotaPeriod { pInStartTime := time.Unix(inputStartTime, 0) pStartTime := time.Unix(startTime, 0) pEndTime := time.Unix(endTime, 0) - period := &QuotaPeriod{inputStartTime: pInStartTime, - startTime: pStartTime, - endTime: pEndTime, + periodData := quotaPeriodData{ + inputStartTime: pInStartTime, + startTime: pStartTime, + endTime: pEndTime, } - return *period + + period := QuotaPeriod{ + quotaPeriodData: periodData, + } + + return period + } func (qp *QuotaPeriod) GetPeriodInputStartTime() time.Time { - return qp.inputStartTime + return qp.quotaPeriodData.inputStartTime } func (qp *QuotaPeriod) GetPeriodStartTime() time.Time { - return qp.startTime + return qp.quotaPeriodData.startTime } func (qp *QuotaPeriod) GetPeriodEndTime() time.Time { - return qp.endTime + return qp.quotaPeriodData.endTime } func (qp *QuotaPeriod) Validate() (bool, error) { @@ -107,7 +117,7 @@ fromUNIXTime := time.Unix(startTime, 0) - quotaBucketDataStruct := "aBucketData{ + quotaBucketDataStruct := quotaBucketData{ EdgeOrgID: edgeOrgID, ID: id, Interval: interval, @@ -121,7 +131,7 @@ } quotaBucket := &QuotaBucket{ - quotaBucketData: *quotaBucketDataStruct, + quotaBucketData: quotaBucketDataStruct, } err := quotaBucket.setCurrentPeriod() @@ -176,15 +186,29 @@ return q.quotaBucketData.StartTime } -func (q *QuotaBucket) GetQuotaType() string { +func (q *QuotaBucket) GetQuotaDescriptorType() string { return q.quotaBucketData.QuotaDescriptorType } -func (q *QuotaBucket) GetPreciseAtSecondsLevel() bool { +func (q *QuotaBucket) GetIsPreciseAtSecondsLevel() bool { return q.quotaBucketData.PreciseAtSecondsLevel } -//Calls setCurrentPeriod if QuotaDescriptorType is rollingWindow or period.endTime is before now. +func (q *QuotaBucket) GetMaxCount() int64 { + return q.quotaBucketData.MaxCount +} + +func (q *QuotaBucket) GetBucketType() string { + return q.quotaBucketData.BucketType +} + +func (q *QuotaBucket) GetWeight() int64 { + return q.quotaBucketData.Weight +} + + +//Calls setCurrentPeriod if DescriptorType is 'rollingWindow' or period.endTime is before now(). +// It is required to setPeriod while incrementing the count. func (q *QuotaBucket) GetPeriod() (*QuotaPeriod, error) { if q.quotaBucketData.QuotaDescriptorType == QuotaTypeRollingWindow { qRWType := RollingWindowQuotaDescriptorType{} @@ -209,7 +233,7 @@ return &q.quotaBucketData.Period, nil } -//setCurrentPeriod only for rolling window else just return the value of QuotaPeriod +//setCurrentPeriod only for rolling window else just return the value of QuotaPeriod. func (q *QuotaBucket) GetQuotaBucketPeriod() (*QuotaPeriod, error) { if q.quotaBucketData.QuotaDescriptorType == QuotaTypeRollingWindow { qRWType := RollingWindowQuotaDescriptorType{} @@ -221,29 +245,23 @@ return &q.quotaBucketData.Period, nil } -func (q *QuotaBucket) GetMaxCount() int64 { - return q.quotaBucketData.MaxCount -} - -func (q *QuotaBucket) GetBucketType() string { - return q.quotaBucketData.BucketType -} - -func (q *QuotaBucket) GetBucketWeight() int64 { - return q.quotaBucketData.Weight -} - func (q *QuotaBucket) SetPeriod(startTime time.Time, endTime time.Time) { - period := QuotaPeriod{inputStartTime: q.GetStartTime(), - startTime: startTime, - endTime: endTime, + periodData := quotaPeriodData{ + inputStartTime: q.GetStartTime(), + startTime: startTime, + endTime: endTime, } + + period := QuotaPeriod{ + quotaPeriodData: periodData, + } + q.quotaBucketData.Period = period } func (q *QuotaBucket) setCurrentPeriod() error { - qDescriptorType, err := GetQuotaDescriptorTypeHandler(q.GetQuotaType()) + qDescriptorType, err := GetQuotaDescriptorTypeHandler(q.GetQuotaDescriptorType()) if err != nil { return err } @@ -253,7 +271,7 @@ func (period *QuotaPeriod) IsCurrentPeriod(qBucket *QuotaBucket) bool { if qBucket != nil && qBucket.GetBucketType() != "" { - if qBucket.GetQuotaType() == QuotaTypeRollingWindow { + if qBucket.GetQuotaDescriptorType() == QuotaTypeRollingWindow { return (period.inputStartTime.Equal(time.Now().UTC()) || period.inputStartTime.Before(time.Now().UTC())) } @@ -271,12 +289,11 @@ maxCount := q.GetMaxCount() exceededCount := false allowedCount := int64(0) - weight := q.GetBucketWeight() + weight := q.GetWeight() period, err := q.GetPeriod() if err != nil { return nil, errors.New("error getting period: " + err.Error()) } - fmt.Println("period set, start time: ", period.GetPeriodStartTime().String(), " end time: ", period.GetPeriodEndTime().String()) //first retrieve the count from counter service. currentCount, err := services.IncrementAndGetCount(q.GetEdgeOrgID(), q.GetID(), 0, period.GetPeriodStartTime().Unix(), period.GetPeriodEndTime().Unix()) @@ -284,28 +301,18 @@ return nil, err } - fmt.Println("currentcount1: ", currentCount) - fmt.Println("startTime get period : ", period.GetPeriodStartTime().String()) - fmt.Println("endTime get period : ", period.GetPeriodEndTime().String()) - if period.IsCurrentPeriod(q) { - if currentCount < maxCount { allowed := maxCount - currentCount - if allowed > weight { - if weight != 0 { currentCount, err = services.IncrementAndGetCount(q.GetEdgeOrgID(), q.GetID(), weight, period.GetPeriodStartTime().Unix(), period.GetPeriodEndTime().Unix()) - fmt.Println("currentcount2: ", currentCount) if err != nil { return nil, err } } - allowedCount = currentCount } else { - if weight != 0 { exceededCount = true @@ -320,14 +327,13 @@ } results := &QuotaBucketResults{ - EdgeOrgID : q.GetEdgeOrgID(), - ID : q.GetID(), - exceededTokens : exceededCount, - allowedTokens : allowedCount, - MaxCount : maxCount, - startedAt : period.GetPeriodStartTime().Unix(), - expiresAt : period.GetPeriodEndTime().Unix(), - + EdgeOrgID: q.GetEdgeOrgID(), + ID: q.GetID(), + exceededTokens: exceededCount, + currentTokens: allowedCount, + MaxCount: maxCount, + startedAt: period.GetPeriodStartTime().Unix(), + expiresAt: period.GetPeriodEndTime().Unix(), } return results, nil
diff --git a/quotaBucket/quotaBucket_test.go b/quotaBucket/quotaBucket_test.go index 3adfce6..aa1cebc 100644 --- a/quotaBucket/quotaBucket_test.go +++ b/quotaBucket/quotaBucket_test.go
@@ -37,6 +37,20 @@ if err == nil { Fail(" Expected error but got <nil>") } + + //startTime same as endTime + period = NewQuotaPeriod(time.Now().UTC().AddDate(0, -1, 0).Unix(), + time.Now().UTC().AddDate(0, 1, 0).Unix(), + time.Now().UTC().AddDate(0, 1, 0).Unix()) + isValid, err = period.Validate() + if isValid { + Fail("Expected isValid false but got true") + } + + if err == nil { + Fail(" Expected error but got <nil>") + } + }) }) @@ -69,7 +83,7 @@ }) var _ = Describe("Test AcceptedQuotaBucketTypes", func() { - It("testTimeUnit", func() { + It("testBucketTypes", func() { if !IsValidQuotaBucketType("synchronous") { Fail("Expected true: synchronous is a valid quotaBucket") } @@ -87,6 +101,7 @@ }) }) +//Tests for QuotaBucket var _ = Describe("QuotaBucket", func() { It("Create with NewQuotaBucket", func() { edgeOrgID := "sampleOrg" @@ -98,11 +113,13 @@ maxCount := int64(10) weight := int64(1) preciseAtSecondsLevel := true + //start time before now() startTime := time.Now().UTC().AddDate(0, -1, 0).Unix() quotaBucket, err := NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, startTime, maxCount, bucketType, weight) Expect(err).NotTo(HaveOccurred()) - + now := time.Now().UTC() + currentHour := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(),0,0,0, time.UTC) err = quotaBucket.Validate() Expect(err).NotTo(HaveOccurred()) @@ -112,16 +129,39 @@ Expect(edgeOrgID).To(Equal(quotaBucket.GetEdgeOrgID())) Expect(id).To(Equal(quotaBucket.GetID())) Expect(timeUnit).To(Equal(quotaBucket.GetTimeUnit())) - Expect(quotaType).To(Equal(quotaBucket.GetQuotaType())) + Expect(quotaType).To(Equal(quotaBucket.GetQuotaDescriptorType())) Expect(bucketType).To(Equal(quotaBucket.GetBucketType())) Expect(interval).To(Equal(quotaBucket.GetInterval())) Expect(maxCount).To(Equal(quotaBucket.GetMaxCount())) - Expect(preciseAtSecondsLevel).To(Equal(quotaBucket.GetPreciseAtSecondsLevel())) + Expect(preciseAtSecondsLevel).To(Equal(quotaBucket.GetIsPreciseAtSecondsLevel())) getPeriod, err := quotaBucket.GetPeriod() Expect(err).NotTo(HaveOccurred()) Expect(getPeriod.GetPeriodInputStartTime().String()).ShouldNot(BeEmpty()) Expect(getPeriod.GetPeriodStartTime().String()).ShouldNot(BeEmpty()) Expect(getPeriod.GetPeriodEndTime().String()).ShouldNot(BeEmpty()) + Expect(getPeriod.GetPeriodStartTime().String()).Should(Equal(currentHour.String())) + Expect(getPeriod.GetPeriodEndTime().String()).Should(Equal(currentHour.Add(time.Hour).String())) + + + //start time is after now() -> should still set period. + startTime = time.Now().UTC().AddDate(0, 1, 0).Unix() + quotaBucket, err = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, startTime, maxCount, bucketType, weight) + Expect(err).NotTo(HaveOccurred()) + + now = time.Now().UTC() + currentHour = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(),0,0,0, time.UTC) + + err = quotaBucket.Validate() + Expect(err).NotTo(HaveOccurred()) + + getPeriod, err = quotaBucket.GetPeriod() + Expect(err).NotTo(HaveOccurred()) + Expect(getPeriod.GetPeriodInputStartTime().String()).ShouldNot(BeEmpty()) + Expect(getPeriod.GetPeriodStartTime().String()).ShouldNot(BeEmpty()) + Expect(getPeriod.GetPeriodEndTime().String()).ShouldNot(BeEmpty()) + Expect(getPeriod.GetPeriodStartTime().String()).Should(Equal(currentHour.String())) + Expect(getPeriod.GetPeriodEndTime().String()).Should(Equal(currentHour.Add(time.Hour).String())) + }) @@ -141,7 +181,7 @@ quotaBucket, err := NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, startTime, maxCount, bucketType, weight) Expect(err).NotTo(HaveOccurred()) - quotaBucket.SetPeriod(time.Now().UTC().UTC().AddDate(0, 1, 0), time.Now().AddDate(0, 0, -1)) + quotaBucket.SetPeriod(time.Now().UTC().AddDate(0, 1, 0), time.Now().UTC().AddDate(0, 0, -1)) err = quotaBucket.Validate() if err == nil { Fail("error expected but got <nil>") @@ -202,7 +242,7 @@ }) var _ = Describe("IsCurrentPeriod", func() { - It("Test RollingType Window Valid TestCase", func() { + It("Test IsCurrentPeriod for RollingType Window - Valid TestCase", func() { edgeOrgID := "sampleOrg" id := "sampleID" @@ -246,7 +286,7 @@ } }) - It("Test RollingType Window InValid TestCase", func() { + It("Test IsCurrentPeriod for RollingType Window - InValid TestCase", func() { edgeOrgID := "sampleOrg" id := "sampleID" @@ -284,7 +324,7 @@ } }) - It("Test calendarType Window Valid TestCases", func() { + It("Test IsCurrentPeriod for calendarType Window - Valid TestCases", func() { edgeOrgID := "sampleOrg" id := "sampleID" @@ -424,7 +464,7 @@ }) - It("Test Non RollingType Window InValid TestCase", func() { + It("Test IsCurrentPeriod for calendarType Window InValid TestCase", func() { edgeOrgID := "sampleOrg" id := "sampleID" @@ -466,7 +506,7 @@ } //start time in period after now - quotaBucket.SetPeriod(time.Now().AddDate(0, 1, 0), time.Now().AddDate(1, 1, 0)) + quotaBucket.SetPeriod(time.Now().UTC().AddDate(0, 1, 0), time.Now().UTC().AddDate(1, 1, 0)) if ok := period.IsCurrentPeriod(quotaBucket); ok { Fail("Exprected true, returned: false")
diff --git a/services/counterServiceHelper.go b/services/counterServiceHelper.go index 13afa98..d0de935 100644 --- a/services/counterServiceHelper.go +++ b/services/counterServiceHelper.go
@@ -18,7 +18,7 @@ key = "key" delta = "delta" startTime = "startTime" - endTime = "endTime" + endTime = "endTime" ) var client *http.Client = &http.Client{