diff --git a/src/jobservice_v2/period/enqueuer_test.go b/src/jobservice_v2/period/enqueuer_test.go new file mode 100644 index 000000000..8c14f358d --- /dev/null +++ b/src/jobservice_v2/period/enqueuer_test.go @@ -0,0 +1,50 @@ +// Copyright 2018 The Harbor Authors. All rights reserved. +package period + +import ( + "sync" + "testing" + "time" + + "github.com/vmware/harbor/src/jobservice_v2/tests" + "github.com/vmware/harbor/src/jobservice_v2/utils" +) + +func TestPeriodicEnqueuerStartStop(t *testing.T) { + ns := tests.GiveMeTestNamespace() + ps := &periodicJobPolicyStore{ + lock: new(sync.RWMutex), + policies: make(map[string]*PeriodicJobPolicy), + } + enqueuer := newPeriodicEnqueuer(ns, redisPool, ps) + enqueuer.start() + <-time.After(100 * time.Millisecond) + enqueuer.stop() +} + +func TestEnqueue(t *testing.T) { + ns := tests.GiveMeTestNamespace() + + pl := &PeriodicJobPolicy{ + PolicyID: "fake_ID", + JobName: "fake_name", + CronSpec: "5 * * * * *", + } + ps := &periodicJobPolicyStore{ + lock: new(sync.RWMutex), + policies: make(map[string]*PeriodicJobPolicy), + } + ps.add(pl) + + enqueuer := newPeriodicEnqueuer(ns, redisPool, ps) + if err := enqueuer.enqueue(); err != nil { + t.Error(err) + } + + err := tests.Clear(utils.RedisKeyScheduled(ns), redisPool.Get()) + err = tests.Clear(utils.KeyJobStats(ns, "fake_ID"), redisPool.Get()) + err = tests.Clear(utils.RedisKeyLastPeriodicEnqueue(ns), redisPool.Get()) + if err != nil { + t.Error(err) + } +} diff --git a/src/jobservice_v2/period/redis_scheduler_test.go b/src/jobservice_v2/period/redis_scheduler_test.go new file mode 100644 index 000000000..c1141bba7 --- /dev/null +++ b/src/jobservice_v2/period/redis_scheduler_test.go @@ -0,0 +1,83 @@ +// Copyright 2018 The Harbor Authors. All rights reserved. +package period + +import ( + "context" + "sync" + "testing" + "time" + + "github.com/vmware/harbor/src/jobservice_v2/env" + "github.com/vmware/harbor/src/jobservice_v2/tests" + "github.com/vmware/harbor/src/jobservice_v2/utils" +) + +var redisPool = tests.GiveMeRedisPool() + +func TestScheduler(t *testing.T) { + scheduler := myPeriodicScheduler() + params := make(map[string]interface{}) + params["image"] = "testing:v1" + id, runAt, err := scheduler.Schedule("fake_job", params, "5 * * * * *") + if err != nil { + t.Error(err) + } + + if time.Now().Unix() >= runAt { + t.Error("the running at time of scheduled job should be after now, but seems not") + } + + if err := scheduler.Load(); err != nil { + t.Error(err) + } + + if scheduler.pstore.size() != 1 { + t.Errorf("expect 1 item in pstore but got '%d'\n", scheduler.pstore.size()) + } + + if err := scheduler.UnSchedule(id); err != nil { + t.Error(err) + } + if err := scheduler.Clear(); err != nil { + t.Error(err) + } + + err = tests.Clear(utils.KeyPeriodicPolicy(tests.GiveMeTestNamespace()), redisPool.Get()) + err = tests.Clear(utils.KeyPeriodicPolicyScore(tests.GiveMeTestNamespace()), redisPool.Get()) + err = tests.Clear(utils.KeyPeriodicNotification(tests.GiveMeTestNamespace()), redisPool.Get()) + if err != nil { + t.Error(err) + } +} + +func TestPubFunc(t *testing.T) { + scheduler := myPeriodicScheduler() + p := &PeriodicJobPolicy{ + PolicyID: "fake_ID", + JobName: "fake_job", + CronSpec: "5 * * * * *", + } + if err := scheduler.AcceptPeriodicPolicy(p); err != nil { + t.Error(err) + } + if scheduler.pstore.size() != 1 { + t.Errorf("expect 1 item in pstore but got '%d' after accepting \n", scheduler.pstore.size()) + } + if rmp := scheduler.RemovePeriodicPolicy("fake_ID"); rmp == nil { + t.Error("expect none nil object returned after removing but got nil") + } + if scheduler.pstore.size() != 0 { + t.Errorf("expect 0 item in pstore but got '%d' \n", scheduler.pstore.size()) + } +} + +func myPeriodicScheduler() *RedisPeriodicScheduler { + sysCtx := context.Background() + ctx := &env.Context{ + SystemContext: sysCtx, + WG: new(sync.WaitGroup), + ErrorChan: make(chan error, 1), + } + + return NewRedisPeriodicScheduler(ctx, tests.GiveMeTestNamespace(), redisPool) +} diff --git a/src/jobservice_v2/period/sweeper_test.go b/src/jobservice_v2/period/sweeper_test.go new file mode 100644 index 000000000..bdb023084 --- /dev/null +++ b/src/jobservice_v2/period/sweeper_test.go @@ -0,0 +1,48 @@ +// Copyright 2018 The Harbor Authors. All rights reserved. +package period + +import ( + "encoding/json" + "testing" + "time" + + "github.com/gocraft/work" + + "github.com/vmware/harbor/src/jobservice_v2/tests" + "github.com/vmware/harbor/src/jobservice_v2/utils" +) + +func TestSweeper(t *testing.T) { + epoch := time.Now().Unix() - 1000 + if err := createFakeScheduledJob(epoch); err != nil { + t.Error(err) + } + ns := tests.GiveMeTestNamespace() + sweeper := NewSweeper(ns, redisPool, work.NewClient(ns, redisPool)) + if err := sweeper.ClearOutdatedScheduledJobs(); err != nil { + t.Error(err) + } + err := tests.Clear(utils.RedisKeyScheduled(ns), redisPool.Get()) + if err != nil { + t.Error(err) + } +} + +func createFakeScheduledJob(runAt int64) error { + fakeJob := make(map[string]interface{}) + fakeJob["name"] = "fake_periodic_job" + fakeJob["id"] = "fake_job_id" + fakeJob["t"] = runAt + fakeJob["args"] = make(map[string]interface{}) + + rawJSON, err := json.Marshal(&fakeJob) + if err != nil { + return err + } + + conn := redisPool.Get() + defer conn.Close() + + _, err = conn.Do("ZADD", utils.RedisKeyScheduled(tests.GiveMeTestNamespace()), runAt, rawJSON) + return err +} diff --git a/src/jobservice_v2/tests/utils.go b/src/jobservice_v2/tests/utils.go new file mode 100644 index 000000000..17c8fe7fb --- /dev/null +++ b/src/jobservice_v2/tests/utils.go @@ -0,0 +1,68 @@ +// Copyright 2018 The Harbor Authors. All rights reserved. + +//Package tests provide test utilities +package tests + +import ( + "errors" + "fmt" + "os" + "time" + + "github.com/garyburd/redigo/redis" +) + +const ( + dialConnectionTimeout = 30 * time.Second + healthCheckPeriod = time.Minute + dialReadTimeout = healthCheckPeriod + 10*time.Second + dialWriteTimeout = 10 * time.Second + testingRedisHost = "REDIS_HOST" + testingNamespace = "testing_job_service_v2" +) + +//GiveMeRedisPool ... +func GiveMeRedisPool() *redis.Pool { + redisHost := getRedisHost() + redisPool := &redis.Pool{ + MaxActive: 2, + MaxIdle: 2, + Wait: true, + Dial: func() (redis.Conn, error) { + return redis.Dial( + "tcp", + fmt.Sprintf("%s:%d", redisHost, 6379), + redis.DialConnectTimeout(dialConnectionTimeout), + redis.DialReadTimeout(dialReadTimeout), + redis.DialWriteTimeout(dialWriteTimeout), + ) + }, + } + + return redisPool +} + +//GiveMeTestNamespace ... +func GiveMeTestNamespace() string { + return testingNamespace +} + +//Clear ... +func Clear(key string, conn redis.Conn) error { + if conn != nil { + defer conn.Close() + _, err := conn.Do("DEL", key) + return err + } + + return errors.New("failed to clear") +} + +func getRedisHost() string { + redisHost := os.Getenv(testingRedisHost) + if redisHost == "" { + redisHost = "10.160.178.186" //for local test + } + + return redisHost +}