Api Validation, CalendarTypeQuotaDescriptor, Tests for QUotaPeriod, QuotaBucket
diff --git a/api_test.go b/api_test.go new file mode 100644 index 0000000..8a83c8f --- /dev/null +++ b/api_test.go
@@ -0,0 +1,9 @@ +package apidQuota_test + +import ( + . "github.com/onsi/ginkgo" +) + +var _ = Describe("Api", func() { + +})
diff --git a/apidQuota_suite_test.go b/apidQuota_suite_test.go new file mode 100644 index 0000000..2c0443d --- /dev/null +++ b/apidQuota_suite_test.go
@@ -0,0 +1,12 @@ +package apidQuota_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "testing" +) + +func TestApidQuota(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "ApidQuota Suite") +}
diff --git a/quotaBucket/QuotaDescriptorType.go b/quotaBucket/QuotaDescriptorType.go deleted file mode 100644 index 3e15c4a..0000000 --- a/quotaBucket/QuotaDescriptorType.go +++ /dev/null
@@ -1,119 +0,0 @@ -package quotaBucket - -import ( - "errors" - "fmt" - "strings" - "time" -) - -const ( - QuotaTypeCalendar = "calendar" // after start time - QuotaTypeFlexi = "flexi" //after first request - QuotaTypeRollingWindow = "rollingWindow" // in the past "window" time -) - -type QuotaDescriptorType interface { - SetCurrentPeriod(bucket *QuotaBucket) error -} - -func GetQuotaTypeHandler(qType string) (QuotaDescriptorType, error) { - var qDescriptor QuotaDescriptorType - quotaType := strings.ToLower(strings.TrimSpace(qType)) - switch quotaType { - case QuotaTypeCalendar: - qDescriptor = &CanlendarQuotaDescriporType{} - return qDescriptor, nil - case QuotaTypeFlexi: - qDescriptor = &FlexiQuotaDescriptorType{} - return qDescriptor, nil - case QuotaTypeRollingWindow: - qDescriptor = &RollingWindowQuotaDescriptorType{} - return qDescriptor, nil - default: - return nil, errors.New("Ignoring unrecognized quota type in request: " + qType) - - } -} - -type CanlendarQuotaDescriporType struct{} - -func (c CanlendarQuotaDescriporType) SetCurrentPeriod(qbucket *QuotaBucket) error { - var err error - startTime := qbucket.GetStartTime() - currentPeriod, err := qbucket.GetPeriod() - if err != nil { - return err - } - - if startTime.Before(time.Now()) || startTime.Equal(time.Now()) { - if currentPeriod != nil { - if currentPeriod.IsCurrentPeriod(qbucket) { - return nil - } - } else { - if currentPeriod.IsCurrentPeriod(qbucket) { - return nil - } else { - qBucketHandler, err := GetQuotaBucketHandler(qbucket.BucketType) - if err != nil { - return errors.New("error getting QuotaBucketType: " + err.Error()) - } - qBucketHandler.resetCount(qbucket) - } - } - } - - var currentStart, currentEnd time.Time - now := time.Now() - timeUnit := strings.ToLower(strings.TrimSpace(qbucket.TimeUnit)) - switch timeUnit { - case TimeUnitSECOND: - currentStart = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, time.UTC) - secInDuration := time.Duration(int64(qbucket.Interval) * time.Second.Nanoseconds()) - currentEnd = currentStart.Add(secInDuration) - break - case TimeUnitMINUTE: - currentStart = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), 0, 0, time.UTC) - minInDuration := time.Duration(int64(qbucket.Interval) * time.Minute.Nanoseconds()) - currentEnd = currentStart.Add(minInDuration) - break - case TimeUnitHOUR: - currentStart = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, time.UTC) - hoursInDuration := time.Duration(int64(qbucket.Interval) * time.Hour.Nanoseconds()) - currentEnd = currentStart.Add(hoursInDuration) - - break - case TimeUnitDAY: - currentStart = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC) - currentEnd = currentStart.AddDate(0, 0, 1*qbucket.Interval) - break - case TimeUnitWEEK: - //todo - //currentStart = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC) - //currentEnd = currentStart.AddDate(0, 0, 7*qbucket.Interval) - break - case TimeUnitMONTH: - currentStart = time.Date(now.Year(), now.Month(), 0, 0, 0, 0, 0, time.UTC) - currentEnd = currentStart.AddDate(0, 1*qbucket.Interval, 0) - break - } - - qbucket.SetPeriod(currentStart, currentEnd) - fmt.Println("inside calendat set period: ", qbucket.quotaBucketData.Period) - return nil -} - -type FlexiQuotaDescriptorType struct{} - -func (c FlexiQuotaDescriptorType) SetCurrentPeriod(qbucket *QuotaBucket) error { - //yet to implement - return nil -} - -type RollingWindowQuotaDescriptorType struct{} - -func (c RollingWindowQuotaDescriptorType) SetCurrentPeriod(qbucket *QuotaBucket) error { - //yet to implement - return nil -}
diff --git a/quotaBucket/apiUtil.go b/quotaBucket/apiUtil.go index c00a879..155a24d 100644 --- a/quotaBucket/apiUtil.go +++ b/quotaBucket/apiUtil.go
@@ -162,12 +162,13 @@ bucketType = value.(string) //fmt.Println("bucketType: ", bucketType) - newQBucket, err := NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, quotaPeriod, startTime, maxCount, bucketType) - if err != nil { - return errors.New("unable to Unmarshal periodMap to quotaPeriod: " + err.Error()) - - } + newQBucket := NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, quotaPeriod, startTime, maxCount, bucketType) qBucket.quotaBucketData = newQBucket.quotaBucketData + + if err := qBucket.Validate(); err != nil { + return errors.New("failed in Validating the quotaBucket: " + err.Error()) + } + return nil }
diff --git a/quotaBucket/quotaBucket.go b/quotaBucket/quotaBucket.go index 36c9082..99bc6ba 100644 --- a/quotaBucket/quotaBucket.go +++ b/quotaBucket/quotaBucket.go
@@ -7,14 +7,41 @@ ) const ( + //add to acceptedTimeUnitList in init() if case any other new timeUnit is added TimeUnitSECOND = "second" TimeUnitMINUTE = "minute" TimeUnitHOUR = "hour" TimeUnitDAY = "day" TimeUnitWEEK = "week" TimeUnitMONTH = "month" + + //add to acceptedBucketTypeList in init() if case any other new bucketType is added + QuotaBucketTypeSynchronous = "synchronous" + QuotaBucketTypeAsynchronous = "asynchronous" + QuotaBucketTypeNonDistributed = "nonDistributed" + //todo: Add other accepted bucketTypes + + //errors + InvalidQuotaTimeUnitType = "invalidQuotaTimeUnitType" + InvalidQuotaBucketType = "invalidQuotaBucketType" + InvalidQuotaPeriod = "invalidQuotaPeriod" ) +var ( + acceptedTimeUnitList map[string]bool + acceptedBucketTypeList map[string]bool +) + +func init() { + + acceptedTimeUnitList = map[string]bool{TimeUnitSECOND: true, + TimeUnitMINUTE: true, TimeUnitHOUR: true, + TimeUnitDAY: true, TimeUnitWEEK: true, TimeUnitMONTH: true} + acceptedBucketTypeList = map[string]bool{QuotaBucketTypeSynchronous: true, + QuotaBucketTypeAsynchronous: true, QuotaBucketTypeNonDistributed: true} //todo: add other accpeted bucketTypes + +} + type QuotaPeriod struct { inputStartTime time.Time startTime time.Time @@ -31,6 +58,25 @@ endTime: pEndTime, } return *period +} + +func (qp *QuotaPeriod) GetPeriodInputStartTime() time.Time { + return qp.inputStartTime +} + +func (qp *QuotaPeriod) GetPeriodStartTime() time.Time { + return qp.startTime +} + +func (qp *QuotaPeriod) GetPeriodEndTime() time.Time { + return qp.endTime +} + +func (qp *QuotaPeriod) Validate() (bool, error) { + if qp.startTime.Before(qp.endTime) { + return true, nil + } + return false, errors.New(InvalidQuotaPeriod + " : startTime in the period must be before endTime") } @@ -53,10 +99,9 @@ func NewQuotaBucket(edgeOrgID string, id string, interval int, timeUnit string, quotaType string, preciseAtSecondsLevel bool, period QuotaPeriod, - startTime int64, maxCount int, bucketType string) (*QuotaBucket, error) { + startTime int64, maxCount int, bucketType string) *QuotaBucket { fromUNIXTime := time.Unix(startTime, 0) - quotaBucketDataStruct := "aBucketData{ EdgeOrgID: edgeOrgID, ID: id, @@ -74,10 +119,33 @@ quotaBucketData: *quotaBucketDataStruct, } - return quotaBucket, nil + return quotaBucket } +func (q *QuotaBucket) Validate() error { + //check if the period is valid + period,err := q.GetQuotaBucketPeriod() + if err != nil { + return err + } + if ok, err := period.Validate(); !ok { + return errors.New("invalid Period: " + err.Error()) + } + + //check valid quotaTimeUnit + if ok := IsValidTimeUnit(q.GetTimeUnit()); !ok { + return errors.New(InvalidQuotaTimeUnitType) + } + + //check valid quotaBucketType + if ok := IsValidQuotaBucketType(q.GetBucketType()); !ok { + return errors.New(InvalidQuotaBucketType) + } + + return nil +} + func (q *QuotaBucket) GetEdgeOrgID() string { return q.quotaBucketData.EdgeOrgID } @@ -90,6 +158,10 @@ return q.quotaBucketData.Interval } +func (q *QuotaBucket) GetTimeUnit() string { + return q.quotaBucketData.TimeUnit +} + func (q *QuotaBucket) GetStartTime() time.Time { return q.quotaBucketData.StartTime } @@ -98,6 +170,11 @@ return q.quotaBucketData.QuotaType } +func (q *QuotaBucket) GetPreciseAtSecondsLevel() bool { + return q.quotaBucketData.PreciseAtSecondsLevel +} + +//Calls setCurrentPeriod if QuotaType is rollingWindow or period.endTime is before now. func (q *QuotaBucket) GetPeriod() (*QuotaPeriod, error) { if q.quotaBucketData.QuotaType == QuotaTypeRollingWindow { qRWType := RollingWindowQuotaDescriptorType{} @@ -106,9 +183,35 @@ return nil, err } } + + period,err := q.GetQuotaBucketPeriod() + if err != nil { + return nil,err + } + //setCurrentPeriod if endTime > time.now() + if period.endTime.Before(time.Now()) || period.endTime.Equal(time.Now()){ + if err := q.setCurrentPeriod(); err != nil { + return nil, err + } + } + return &q.quotaBucketData.Period, nil } +//setCurrentPeriod only for rolling window else just return the value of QuotaPeriod +func (q *QuotaBucket) GetQuotaBucketPeriod() (*QuotaPeriod,error) { + if q.quotaBucketData.QuotaType == QuotaTypeRollingWindow { + qRWType := RollingWindowQuotaDescriptorType{} + err := qRWType.SetCurrentPeriod(q) + if err != nil { + return nil, err + } + } + return &q.quotaBucketData.Period,nil +} + + + func (q *QuotaBucket) GetMaxCount() int { return q.quotaBucketData.MaxCount } @@ -117,11 +220,12 @@ return q.quotaBucketData.BucketType } -func (q *quotaBucketData) SetPeriod(startTime time.Time, endTime time.Time) { - q.Period = QuotaPeriod{inputStartTime: q.StartTime, +func (q *QuotaBucket) SetPeriod(startTime time.Time, endTime time.Time) { + period := QuotaPeriod{inputStartTime: q.GetStartTime(), startTime: startTime, endTime: endTime, } + q.quotaBucketData.Period = period } func (q *QuotaBucket) setCurrentPeriod() error { @@ -136,13 +240,16 @@ func (period *QuotaPeriod) IsCurrentPeriod(qBucket *QuotaBucket) bool { if qBucket != nil && qBucket.GetBucketType() != "" { - if qBucket.GetBucketType() == QuotaTypeRollingWindow { - return (period.inputStartTime.Equal(time.Now()) || period.inputStartTime.Before(time.Now())) + if qBucket.GetQuotaType() == QuotaTypeRollingWindow { + return (period.inputStartTime.Equal(time.Now()) || period.inputStartTime.Before(time.Now()) ) } - return ((period.inputStartTime.Equal(time.Now()) || period.inputStartTime.Before(time.Now())) && - period.startTime.String() != "" && period.endTime.String() != "" && - period.startTime.Before(time.Now()) && period.startTime.Equal(time.Now()) && - period.endTime.Before(time.Now()) && period.startTime.Equal(time.Now())) + + return (period.inputStartTime.Equal(time.Now()) || period.inputStartTime.Before(time.Now())) && + period.startTime.String() != "" && + period.endTime.String() != "" && + period.startTime.Before(period.endTime) && + (period.startTime.Equal(time.Now()) || period.startTime.Before(time.Now()))&& + (period.endTime.Equal(time.Now()) || period.endTime.After(time.Now())) } return false } @@ -167,3 +274,17 @@ //todo return 0, nil } + +func IsValidTimeUnit(timeUnit string) bool { + if _, ok := acceptedTimeUnitList[timeUnit]; ok { + return true + } + return false +} + +func IsValidQuotaBucketType(bucketType string) bool { + if _, ok := acceptedBucketTypeList[bucketType]; ok { + return true + } + return false +}
diff --git a/quotaBucket/quotaBucketType.go b/quotaBucket/quotaBucketType.go index 843846b..1eb051a 100644 --- a/quotaBucket/quotaBucketType.go +++ b/quotaBucket/quotaBucketType.go
@@ -5,13 +5,6 @@ "strings" ) -const ( - QuotaBucketTypeSynchronous = "synchronous" - QuotaBucketTypeAsynchronous = "asynchronous" - QuotaBucketTypeNonDistributed = "nonDistributed" - //todo: Add other bucketTypes -) - type QuotaBucketType interface { resetCount(bucket *QuotaBucket) error }
diff --git a/quotaBucket/quotaBucketType_test.go b/quotaBucket/quotaBucketType_test.go new file mode 100644 index 0000000..70ee53d --- /dev/null +++ b/quotaBucket/quotaBucketType_test.go
@@ -0,0 +1,9 @@ +package quotaBucket_test + +import ( + . "github.com/onsi/ginkgo" +) + +var _ = Describe("QuotaBucketType", func() { + +})
diff --git a/quotaBucket/quotaBucket_suite_test.go b/quotaBucket/quotaBucket_suite_test.go new file mode 100644 index 0000000..b05019b --- /dev/null +++ b/quotaBucket/quotaBucket_suite_test.go
@@ -0,0 +1,22 @@ +package quotaBucket_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "fmt" + "testing" +) + +func TestQuotaBucket(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "QuotaBucket Suite") +} + +var _ = BeforeSuite(func() { + fmt.Println("before suite") + +}) + +var _ = AfterSuite(func() { + fmt.Println("after suite") +})
diff --git a/quotaBucket/quotaBucket_test.go b/quotaBucket/quotaBucket_test.go new file mode 100644 index 0000000..df50e82 --- /dev/null +++ b/quotaBucket/quotaBucket_test.go
@@ -0,0 +1,507 @@ +package quotaBucket_test + +import ( + . "github.com/30x/apidQuota/quotaBucket" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "strings" + "time" +) + +var _ = Describe("Test QuotaPeriod", func() { + It("Valid NewQuotaPeriod", func() { + //startTime before endTime + period := NewQuotaPeriod(1492324596, 1490047028, 1492725428) + isValid, err := period.Validate() + + if !isValid || err != nil { + Fail("expected isValid: true and error: nil for NewQuotaPeriod") + } + }) + + It("Invalid NewQuotaPeriod", func() { + //startTime after endTime + period := NewQuotaPeriod(1492324596, 1492725428, 1490047028) + isValid, err := period.Validate() + if err == nil || isValid { + Fail("Expected isValid: false and error: <notNil> for invalid NewQuotaPeriod. startTime should be before endTime") + } + }) + +}) + +var _ = Describe("Test AcceptedQuotaTimeUnitTypes", func() { + It("testTimeUnit", func() { + if !IsValidTimeUnit("second") { + Fail("second is a valid TimeUnit") + } + if !IsValidTimeUnit("minute") { + Fail("minute is a valid TimeUnit") + } + if !IsValidTimeUnit("hour") { + Fail("hour is a valid TimeUnit") + } + if !IsValidTimeUnit("day") { + Fail("day is a valid TimeUnit") + } + if !IsValidTimeUnit("week") { + Fail("week is a valid TimeUnit") + } + if !IsValidTimeUnit("month") { + Fail("month is a valid TimeUnit") + } + + //invalid type + if IsValidTimeUnit("invalidType") { + Fail("invalidType is a invalid TimeUnit") + } + }) +}) + +var _ = Describe("Test AcceptedQuotaBucketTypes", func() { + It("testTimeUnit", func() { + if !IsValidQuotaBucketType("synchronous") { + Fail("synchronous is a valid quotaBucket") + } + if !IsValidQuotaBucketType("asynchronous") { + Fail("asynchronous is a valid quotaBucket") + } + if !IsValidQuotaBucketType("nonDistributed") { + Fail("nonDistributed is a valid quotaBucket") + } + + //invalid type + if IsValidQuotaBucketType("invalidType") { + Fail("invalidType is a invalid quotaBucket") + } + }) +}) + +var _ = Describe("QuotaBucket", func() { + It("Create with NewQuotaBucket", func() { + edgeOrgID := "sampleOrg" + id := "sampleID" + timeUnit := "hour" + quotaType := "calendar" + bucketType := "synchronous" + interval := 1 + maxCount := 10 + preciseAtSecondsLevel := true + period := NewQuotaPeriod(time.Now().AddDate(0,-1,0).Unix(), + time.Now().AddDate(0,0,-1).Unix(), + time.Now().AddDate(0,1,0).Unix()) + startTime := int64(1492324596) + + quotaBucket := NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType) + err := quotaBucket.Validate() + Expect(err).NotTo(HaveOccurred()) + + + //also check if all the fields are set as expected + sTime := time.Unix(startTime, 0) + Expect(sTime).To(Equal(quotaBucket.GetStartTime())) + 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(bucketType).To(Equal(quotaBucket.GetBucketType())) + Expect(interval).To(Equal(quotaBucket.GetInterval())) + Expect(maxCount).To(Equal(quotaBucket.GetMaxCount())) + Expect(preciseAtSecondsLevel).To(Equal(quotaBucket.GetPreciseAtSecondsLevel())) + getPeriod, err := quotaBucket.GetPeriod() + Expect(err).NotTo(HaveOccurred()) + Expect(period).To(Equal(*getPeriod)) + + }) + + It("Test invalid quotaPeriod", func() { + edgeOrgID := "sampleOrg" + id := "sampleID" + timeUnit := "hour" + quotaType := "calendar" + bucketType := "synchronous" + interval := 1 + maxCount := 10 + preciseAtSecondsLevel := true + period := NewQuotaPeriod(1492324596, 1492725428, 1490047028) + startTime := int64(1492324596) + + quotaBucket := NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType) + err := quotaBucket.Validate() + if err == nil { + Fail("error expected but got <nil>") + } + if !strings.Contains(err.Error(), InvalidQuotaPeriod) { + Fail("expected: " + InvalidQuotaPeriod + " in the error but got: " + err.Error()) + } + + }) + + It("Test invalid timeUnitType", func() { + edgeOrgID := "sampleOrg" + id := "sampleID" + timeUnit := "invalidTimeUnit" + quotaType := "calendar" + bucketType := "synchronous" + interval := 1 + maxCount := 10 + preciseAtSecondsLevel := true + period := NewQuotaPeriod(time.Now().AddDate(0,-1,0).Unix(), + time.Now().AddDate(0,0,-1).Unix(), + time.Now().AddDate(0,1,0).Unix()) + startTime := int64(1492324596) + + quotaBucket := NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType) + err := quotaBucket.Validate() + if err == nil { + Fail("error expected but got <nil>") + } + if err.Error() != InvalidQuotaTimeUnitType { + Fail("expected: " + InvalidQuotaBucketType + "but got: " + err.Error()) + } + + }) + + It("Test invalid quotaBucketType", func() { + edgeOrgID := "sampleOrg" + id := "sampleID" + timeUnit := "hour" + quotaType := "calendar" + bucketType := "invalidQuotaBucket" + interval := 1 + maxCount := 10 + preciseAtSecondsLevel := true + period := NewQuotaPeriod(time.Now().AddDate(0,-1,0).Unix(), + time.Now().AddDate(0,0,-1).Unix(), + time.Now().AddDate(0,1,0).Unix()) + startTime := time.Now().AddDate(0,-1,0).Unix() + + quotaBucket := NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType) + err := quotaBucket.Validate() + if err == nil { + Fail("error expected but got <nil>") + } + if err.Error() != InvalidQuotaBucketType { + Fail("expected: " + InvalidQuotaBucketType + "but got: " + err.Error()) + } + + }) + +}) + + + + +var _ = Describe("IsCurrentPeriod", func(){ + It("Test RollingType Window Valid TestCase", func() { + + edgeOrgID := "sampleOrg" + id := "sampleID" + timeUnit := "hour" + quotaType := "rollingwindow" + bucketType := "synchronous" + interval := 1 + maxCount := 10 + preciseAtSecondsLevel := true + //InputStart time is before now + period := NewQuotaPeriod(time.Now().AddDate(0, -1,0).Unix(), + time.Now().AddDate(0,0, -1).Unix(), + time.Now().AddDate(0,1,0).Unix()) + startTime := time.Now().AddDate(0,-1,0).Unix() + + quotaBucket := NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType) + err := quotaBucket.Validate() + Expect(err).NotTo(HaveOccurred()) + if ok := period.IsCurrentPeriod(quotaBucket); !ok{ + Fail("Exprected true, returned: false") + } + + //InputStart time is now + period = NewQuotaPeriod(time.Now().Unix(), + time.Now().AddDate(0,0,-1).Unix(), + time.Now().AddDate(0,1,0).Unix()) + startTime = time.Now().Unix() + quotaBucket = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType) + err = quotaBucket.Validate() + Expect(err).NotTo(HaveOccurred()) + + + period.IsCurrentPeriod(quotaBucket) + if ok := period.IsCurrentPeriod(quotaBucket); !ok{ + Fail("Exprected true, returned: false") + } + }) + + It("Test RollingType Window InValid TestCase", func() { + + edgeOrgID := "sampleOrg" + id := "sampleID" + timeUnit := "hour" + quotaType := "rollingwindow" + bucketType := "synchronous" + interval := 1 + maxCount := 10 + preciseAtSecondsLevel := true + //InputStart time is after now. + period := NewQuotaPeriod(time.Now().AddDate(0,1,0).Unix(), + time.Now().AddDate(0,1,0).Unix(), time.Now().AddDate(0,0,1).Unix()) + startTime := time.Now().AddDate(0,1,0).Unix() + + quotaBucket := NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType) + err := quotaBucket.Validate() + Expect(err).NotTo(HaveOccurred()) + + + if ok := period.IsCurrentPeriod(quotaBucket); ok{ + Fail("Exprected true, returned: false") + } + + //endTime before startTime in period + startTime = time.Now().AddDate(0,-1,0).Unix() + quotaBucket = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType) + quotaBucket.SetPeriod(time.Now(), time.Now().AddDate(0,1,0)) + if ok := period.IsCurrentPeriod(quotaBucket); ok{ + Fail("Exprected false, returned: true") + } + }) + + + It("Test NonRollingType Window Valid TestCases", func() { + + edgeOrgID := "sampleOrg" + id := "sampleID" + timeUnit := "hour" + quotaType := "calendar" + bucketType := "synchronous" + interval := 1 + maxCount := 10 + preciseAtSecondsLevel := true + + + //InputStart time is before now + period := NewQuotaPeriod(time.Now().AddDate(0, -1,0).Unix(), + time.Now().AddDate(0,0, -1).Unix(), + time.Now().AddDate(0,1,0).Unix()) + startTime := time.Now().AddDate(0,-1,0).Unix() + + quotaBucket := NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType) + err := quotaBucket.Validate() + Expect(err).NotTo(HaveOccurred()) + + if ok := period.IsCurrentPeriod(quotaBucket); !ok{ + Fail("Exprected true, returned: false") + } + + + //InputStart time is now + period = NewQuotaPeriod(time.Now().Unix(), + time.Now().AddDate(0,0,-1).Unix(), + time.Now().AddDate(0,1,0).Unix()) + startTime = time.Now().Unix() + quotaBucket = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType) + err = quotaBucket.Validate() + Expect(err).NotTo(HaveOccurred()) + + period.IsCurrentPeriod(quotaBucket) + if ok := period.IsCurrentPeriod(quotaBucket); !ok{ + Fail("Exprected true, returned: false") + } + + //start Time in period is before now + startTime = time.Now().Unix() + period = NewQuotaPeriod(time.Now().AddDate(0,-1,0).Unix(), + time.Now().AddDate(0,0,-1).Unix(), + time.Now().AddDate(0,1,0).Unix()) + quotaBucket = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType) + err = quotaBucket.Validate() + Expect(err).NotTo(HaveOccurred()) + + period.IsCurrentPeriod(quotaBucket) + if ok := period.IsCurrentPeriod(quotaBucket); !ok{ + Fail("Exprected true, returned: false") + } + + //start Time in period is now + startTime = time.Now().Unix() + period = NewQuotaPeriod(time.Now().AddDate(0,-1,0).Unix(), + time.Now().Unix(), + time.Now().AddDate(0,1,0).Unix()) + quotaBucket = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType) + err = quotaBucket.Validate() + Expect(err).NotTo(HaveOccurred()) + + period.IsCurrentPeriod(quotaBucket) + if ok := period.IsCurrentPeriod(quotaBucket); !ok{ + Fail("Exprected true, returned: false") + } + + //end Time in period is now // cant set end time to now and tes.. by the time it evaluates isCurrentPeriod the period.endTime will be before time.now() + //fmt.Println("entTIme is now : ") + //startTime = time.Now().Unix() + //period = NewQuotaPeriod(time.Now().AddDate(0,-1,-1).Unix(), + // time.Now().AddDate(0,0,-1).Unix(), + // time.Now().Unix()) + //quotaBucket = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType) + //err = quotaBucket.Validate() + //if err != nil { + // Fail("no error expected but got error: " + err.Error()) + //} + // + //period.IsCurrentPeriod(quotaBucket) + //if ok := period.IsCurrentPeriod(quotaBucket); !ok{ + // Fail("Exprected true, returned: false") + //} + + //end Time in period is after now + startTime = time.Now().Unix() + period = NewQuotaPeriod(time.Now().AddDate(0,-1,0).Unix(), + time.Now().AddDate(0,0,-1).Unix(), + time.Now().AddDate(0,1,0).Unix()) + quotaBucket = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType) + err = quotaBucket.Validate() + Expect(err).NotTo(HaveOccurred()) + + period.IsCurrentPeriod(quotaBucket) + if ok := period.IsCurrentPeriod(quotaBucket); !ok{ + Fail("Exprected true, returned: false") + } + + //start time in period is before end time + startTime = time.Now().Unix() + period = NewQuotaPeriod(time.Now().AddDate(0,-1,0).Unix(), + time.Now().AddDate(0,-1,0).Unix(), + time.Now().AddDate(0,1,0).Unix()) + quotaBucket = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType) + err = quotaBucket.Validate() + Expect(err).NotTo(HaveOccurred()) + + period.IsCurrentPeriod(quotaBucket) + if ok := period.IsCurrentPeriod(quotaBucket); !ok{ + Fail("Exprected true, returned: false") + } + + }) + + It("Test Non RollingType Window InValid TestCase", func() { + + edgeOrgID := "sampleOrg" + id := "sampleID" + timeUnit := "hour" + quotaType := "calendar" + bucketType := "synchronous" + interval := 1 + maxCount := 10 + preciseAtSecondsLevel := true + + //InputStart time is after now. + period := NewQuotaPeriod(time.Now().AddDate(0,1,0).Unix(), + time.Now().AddDate(0,1,0).Unix(), time.Now().AddDate(1,0,1).Unix()) + startTime := time.Now().AddDate(0,1,0).Unix() + + quotaBucket := NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType) + err := quotaBucket.Validate() + Expect(err).NotTo(HaveOccurred()) + + if ok := period.IsCurrentPeriod(quotaBucket); ok{ + Fail("Exprected true, returned: false") + } + + + //endTime is before start time + startTime = time.Now().AddDate(0,-1,0).Unix() + quotaBucket = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType) + err = quotaBucket.Validate() + Expect(err).NotTo(HaveOccurred()) + + quotaBucket.SetPeriod(time.Now(), time.Now().AddDate(0,-1,0)) + + if ok := period.IsCurrentPeriod(quotaBucket); ok{ + Fail("Exprected true, returned: false") + } + + //start time in period after now + quotaBucket.SetPeriod(time.Now().AddDate(0,1,0), time.Now().AddDate(1,1,0)) + + if ok := period.IsCurrentPeriod(quotaBucket); ok{ + Fail("Exprected true, returned: false") + } + + //end time in period is before now + quotaBucket.SetPeriod(time.Now().AddDate(-1,-1,0), time.Now().AddDate(0,-1,0)) + + if ok := period.IsCurrentPeriod(quotaBucket); ok{ + Fail("Exprected true, returned: false") + } + + }) +}) + + +var _ = Describe("Test GetPeriod and setCurrentPeriod", func() { + It("Valid GetPeriod", func() { + edgeOrgID := "sampleOrg" + id := "sampleID" + timeUnit := "hour" + quotaType := "rollingwindow" + bucketType := "synchronous" + interval := 1 + maxCount := 10 + preciseAtSecondsLevel := true + //InputStart time is before now + period := NewQuotaPeriod(time.Now().AddDate(0, -1,0).Unix(), + time.Now().AddDate(0,0, -1).Unix(), + time.Now().AddDate(0,1,0).Unix()) + startTime := time.Now().AddDate(0,-1,0).Unix() + quotaBucket := NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType) + err := quotaBucket.Validate() + Expect(err).NotTo(HaveOccurred()) + qPeriod, err := quotaBucket.GetPeriod() + Expect(err).NotTo(HaveOccurred()) + + // check if the rolling window was set properly + Expect(qPeriod.GetPeriodInputStartTime()).Should(Equal(quotaBucket.GetStartTime())) + if !qPeriod.GetPeriodEndTime().After(qPeriod.GetPeriodStartTime()){ + Fail("Rolling Window was not set as expected") + } + intervalDuration := qPeriod.GetPeriodEndTime().Sub(qPeriod.GetPeriodStartTime()) + expectedDuration, err := GetIntervalDurtation(quotaBucket) + Expect(intervalDuration).Should(Equal(expectedDuration)) + + + //for non rolling Type window do not setCurrentPeriod as endTime is > time.now. + quotaType = "calendar" + pstartTime := time.Now().AddDate(0,-1,0) + pendTime := time.Now().AddDate(0,1,0) + quotaBucket = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType) + quotaBucket.SetPeriod(pstartTime, pendTime) + qPeriod, err = quotaBucket.GetPeriod() + Expect(err).NotTo(HaveOccurred()) + // check if the calendar window was set properly + Expect(qPeriod.GetPeriodInputStartTime()).Should(Equal(quotaBucket.GetStartTime())) + if !qPeriod.GetPeriodEndTime().After(qPeriod.GetPeriodStartTime()){ + Fail("Rolling Window was not set as expected") + } + + //for non rolling Type window setCurrentPeriod as endTime is < time.now. + quotaType = "calendar" + pstartTime = time.Now().AddDate(0,-1,0) + pendTime = time.Now().AddDate(0,-1,0) + quotaBucket = NewQuotaBucket(edgeOrgID, id, interval, timeUnit, quotaType, preciseAtSecondsLevel, period, startTime, maxCount, bucketType) + quotaBucket.SetPeriod(pstartTime, pendTime) + qPeriod, err = quotaBucket.GetPeriod() + Expect(err).NotTo(HaveOccurred()) + // check if the calendar window was set properly + Expect(qPeriod.GetPeriodInputStartTime()).Should(Equal(quotaBucket.GetStartTime())) + if !qPeriod.GetPeriodEndTime().After(qPeriod.GetPeriodStartTime()){ + Fail("Rolling Window was not set as expected") + } + intervalDuration = qPeriod.GetPeriodEndTime().Sub(qPeriod.GetPeriodStartTime()) + expectedDuration, err = GetIntervalDurtation(quotaBucket) + Expect(intervalDuration).Should(Equal(expectedDuration)) + + + + }) + +}) +
diff --git a/quotaBucket/quotaDescriptorType.go b/quotaBucket/quotaDescriptorType.go new file mode 100644 index 0000000..c94333c --- /dev/null +++ b/quotaBucket/quotaDescriptorType.go
@@ -0,0 +1,155 @@ +package quotaBucket + +import ( + "errors" + "fmt" + "strings" + "time" +) + +const ( + QuotaTypeCalendar = "calendar" // after start time + QuotaTypeFlexi = "flexi" //after first request + QuotaTypeRollingWindow = "rollingwindow" // in the past "window" time +) + +type QuotaDescriptorType interface { + SetCurrentPeriod(bucket *QuotaBucket) error +} + +func GetQuotaTypeHandler(qType string) (QuotaDescriptorType, error) { + var qDescriptor QuotaDescriptorType + quotaType := strings.ToLower(strings.TrimSpace(qType)) + switch quotaType { + case QuotaTypeCalendar: + qDescriptor = &CalendarQuotaDescriptorType{} + return qDescriptor, nil + case QuotaTypeRollingWindow: + qDescriptor = &RollingWindowQuotaDescriptorType{} + return qDescriptor, nil + default: + return nil, errors.New("Quota type " + qType + " in the request is not supported") + + } +} + +type CalendarQuotaDescriptorType struct{} + +func (c CalendarQuotaDescriptorType) SetCurrentPeriod(qbucket *QuotaBucket) error { + startTime := qbucket.GetStartTime() + currentPeriod,err := qbucket.GetQuotaBucketPeriod() +if err != nil { + return err +} + if startTime.Before(time.Now()) || startTime.Equal(time.Now()) { + if currentPeriod != nil { + if currentPeriod.IsCurrentPeriod(qbucket) { + return nil + } + } else { + if currentPeriod.IsCurrentPeriod(qbucket) { + return nil + } else { + qBucketHandler, err := GetQuotaBucketHandler(qbucket.BucketType) + if err != nil { + return errors.New("error getting QuotaBucketType: " + err.Error()) + } + qBucketHandler.resetCount(qbucket) + } + } + } + + var currentStart, currentEnd time.Time + now := time.Now() + timeUnit := strings.ToLower(strings.TrimSpace(qbucket.TimeUnit)) + switch timeUnit { + case TimeUnitSECOND: + currentStart = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, time.UTC) + secInDuration := time.Duration(int64(qbucket.Interval) * time.Second.Nanoseconds()) + currentEnd = currentStart.Add(secInDuration) + break + case TimeUnitMINUTE: + currentStart = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), 0, 0, time.UTC) + minInDuration := time.Duration(int64(qbucket.Interval) * time.Minute.Nanoseconds()) + currentEnd = currentStart.Add(minInDuration) + break + case TimeUnitHOUR: + currentStart = time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, time.UTC) + hoursInDuration := time.Duration(int64(qbucket.Interval) * time.Hour.Nanoseconds()) + currentEnd = currentStart.Add(hoursInDuration) + + break + case TimeUnitDAY: + currentStart = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC) + currentEnd = currentStart.AddDate(0, 0, 1*qbucket.Interval) + break + case TimeUnitWEEK: + //todo + currentStart = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC) + for currentStart.Weekday() != time.Monday { + currentStart = currentStart.AddDate(0, 0, -1) + } + currentEnd = currentStart.AddDate(0, 0, 7*qbucket.Interval) + break + case TimeUnitMONTH: + currentStart = time.Date(now.Year(), now.Month(), 0, 0, 0, 0, 0, time.UTC) + currentEnd = currentStart.AddDate(0, qbucket.Interval, 0) + break + } + + qbucket.SetPeriod(currentStart, currentEnd) + fmt.Println("inside calendar set period: ", qbucket.quotaBucketData.Period) + return nil +} + +type RollingWindowQuotaDescriptorType struct{} + +func (c RollingWindowQuotaDescriptorType) SetCurrentPeriod(qbucket *QuotaBucket) error { + //yet to implement + var currentStart, currentEnd time.Time + currentEnd = time.Now() + interval, err := GetIntervalDurtation(qbucket) + if err != nil { + return errors.New("error in SetCurrentPeriod: " + err.Error()) + } + currentStart = currentEnd.Add(-interval) + qbucket.SetPeriod(currentStart, currentEnd) + + return nil +} +func GetIntervalDurtation(qb *QuotaBucket) (time.Duration, error) { + timeUnit := strings.ToLower(strings.TrimSpace(qb.TimeUnit)) + switch timeUnit { + case TimeUnitSECOND: + return time.Duration(int64(qb.Interval) * time.Second.Nanoseconds()), nil + case TimeUnitMINUTE: + return time.Duration(int64(qb.Interval) * time.Minute.Nanoseconds()), nil + case TimeUnitHOUR: + return time.Duration(int64(qb.Interval) * time.Hour.Nanoseconds()), nil + case TimeUnitDAY: + return time.Duration(int64(qb.Interval*24) * time.Hour.Nanoseconds()), nil + case TimeUnitWEEK: + return time.Duration(int64(qb.Interval*24*7) * time.Hour.Nanoseconds()), nil + case TimeUnitMONTH: + now := time.Now() + var currentStart, currentEnd time.Time + quotaType := strings.ToLower(strings.TrimSpace(qb.QuotaType)) + switch quotaType { + case QuotaTypeCalendar: + currentStart = time.Date(now.Year(), now.Month(), 0, 0, 0, 0, 0, time.UTC) + currentEnd = currentStart.AddDate(0, qb.Interval, 0) + return currentEnd.Sub(currentStart), nil + case QuotaTypeRollingWindow: + currentEnd = now + currentStart = currentEnd.AddDate(0, -qb.Interval, 0) + return currentEnd.Sub(currentStart), nil + default: + return time.Duration(0), errors.New("Ignoring unrecognized quotaType : " + quotaType) + + } + default: + return time.Duration(0), errors.New("Ignoring unrecognized timeUnit : " + timeUnit) + + } + +}
diff --git a/quotaBucket/quotaDescriptorType_test.go b/quotaBucket/quotaDescriptorType_test.go new file mode 100644 index 0000000..22a4a08 --- /dev/null +++ b/quotaBucket/quotaDescriptorType_test.go
@@ -0,0 +1,9 @@ +package quotaBucket_test + +import ( + . "github.com/onsi/ginkgo" +) + +var _ = Describe("QuotaDescriptorType", func() { + +})