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() {
+
+})