Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add: GetJob, DeleteJob, ListJobsByPrefix #79

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ cron.AddJob(Job{
})
```

## Tests

Pre-requisites to run the tests locally:
- [Install etcd](https://etcd.io/docs/v3.4/install/)
- Launch etcd: `etcd --logger=zap`
- Proceed to run tests: `go test`

## Release a New Version

Bump new version number in `CHANGELOG.md` and `README.md`.
Expand Down
41 changes: 41 additions & 0 deletions cron.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,16 @@ func New(opts ...CronOpt) (*Cron, error) {
return cron, nil
}

// GetJob retrieves a job by name.
func (c *Cron) GetJob(jobName string) *Job {
for _, entry := range c.entries {
if entry.Job.Name == jobName {
return &entry.Job
}
}
return nil
}

// AddFunc adds a Job to the Cron to be run on the given schedule.
func (c *Cron) AddJob(job Job) error {
schedule, err := Parse(job.Rhythm)
Expand All @@ -174,6 +184,25 @@ func (c *Cron) AddJob(job Job) error {
return nil
}

// DeleteJob deletes a job by name.
func (c *Cron) DeleteJob(jobName string) error {
var updatedEntries []*Entry
found := false
for _, entry := range c.entries {
if entry.Job.Name == jobName {
found = true
continue
}
// Keep the entries that don't match the specified jobName
updatedEntries = append(updatedEntries, entry)
}
if !found {
return fmt.Errorf("job not found: %s", jobName)
}
c.entries = updatedEntries
return nil
}

// Schedule adds a Job to the Cron to be run on the given schedule.
func (c *Cron) Schedule(schedule Schedule, job Job) {
entry := &Entry{
Expand All @@ -188,6 +217,18 @@ func (c *Cron) Schedule(schedule Schedule, job Job) {
c.add <- entry
}

// ListJobsByPrefix returns the list of jobs with the relevant prefix
func (c *Cron) ListJobsByPrefix(prefix string) []*Job {
var prefixJobs []*Job
for _, entry := range c.entries {
if strings.HasPrefix(entry.Job.Name, prefix) {
// Job belongs to the specified prefix
prefixJobs = append(prefixJobs, &entry.Job)
}
}
return prefixJobs
}

// Entries returns a snapshot of the cron entries.
func (c *Cron) Entries() []*Entry {
if c.running {
Expand Down
119 changes: 119 additions & 0 deletions cron_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,125 @@ func TestJob(t *testing.T) {
}
}

// Add some jobs, try to ListJobsByPrefix
func TestListJobsByPrefix(t *testing.T) {
wg := &sync.WaitGroup{}
wg.Add(2)

cron, err := New()
if err != nil {
t.Fatal("unexpected error")
}
defer cron.Stop()

// Add jobs with different prefixes
cron.AddJob(Job{Name: "prefix_test_job1", Rhythm: "* * * * * ?", Func: func(context.Context) error { wg.Done(); return nil }})
cron.AddJob(Job{Name: "prefix_test_job2", Rhythm: "* * * * * ?", Func: func(context.Context) error { wg.Done(); return nil }})
cron.AddJob(Job{Name: "other_job", Rhythm: "* * * * * ?", Func: func(context.Context) error { return nil }})

cron.Start(context.Background())

// Ensure only jobs with the specified prefix are returned
prefixJobs := cron.ListJobsByPrefix("prefix_test")
if len(prefixJobs) != 2 {
t.Errorf("ListJobsByPrefix did not return the correct number of jobs. Expected: 2, Actual: %d", len(prefixJobs))
t.FailNow()
}

select {
case <-time.After(ONE_SECOND):
t.FailNow()
case <-wait(wg):
}
}

// Add a job, then DeleteJob
func TestDeleteJob(t *testing.T) {
wg := &sync.WaitGroup{}
wg.Add(1)

cron, err := New()
if err != nil {
t.Fatal("unexpected error")
}
defer cron.Stop()

cron.AddJob(Job{Name: "delete_test_job", Rhythm: "* * * * * ?", Func: func(context.Context) error { wg.Done(); return nil }})

// Ensure the job is in the entries before deletion
foundBeforeDeletion := false
for _, entry := range cron.Entries() {
if entry.Job.Name == "delete_test_job" {
foundBeforeDeletion = true
break
}
}

if !foundBeforeDeletion {
t.Error("Job not found in entries before deletion")
t.FailNow()
}

cron.Start(context.Background())

err = cron.DeleteJob("delete_test_job")
if err != nil {
t.Errorf("Error deleting job: %v", err)
t.FailNow()
}

// Ensure the job is no longer in the entries after deletion
foundAfterDeletion := false
for _, entry := range cron.Entries() {
if entry.Job.Name == "delete_test_job" {
foundAfterDeletion = true
break
}
}

if foundAfterDeletion {
t.Error("DeleteJob did not remove the job from entries")
t.FailNow()
}

// Ensure the job is not triggered after deletion
select {
case <-time.After(ONE_SECOND):
// This is expected since the job should not be triggered
case <-wait(wg):
t.Error("Job was triggered after deletion")
}
}

// Add a job, then GetJob
func TestGetJob(t *testing.T) {
wg := &sync.WaitGroup{}
wg.Add(1)

cron, err := New()
if err != nil {
t.Fatal("unexpected error")
}
defer cron.Stop()

jobName := "get_test_job"
cron.AddJob(Job{Name: jobName, Rhythm: "* * * * * ?", Func: func(context.Context) error { wg.Done(); return nil }})

cron.Start(context.Background())

job := cron.GetJob(jobName)
if job == nil || job.Name != jobName {
t.Error("GetJob did not return the expected job")
t.FailNow()
}

select {
case <-time.After(ONE_SECOND):
t.FailNow()
case <-wait(wg):
}
}

// TestCron_Parallel tests that with 2 crons with the same job
// They should only execute once each job event
func TestCron_Parallel(t *testing.T) {
Expand Down