mirror of
https://github.com/F1bonacc1/process-compose.git
synced 2024-08-17 23:40:39 +03:00
Circular dependency check
This commit is contained in:
parent
9fb6eaa132
commit
08ddae986e
@ -8,18 +8,13 @@ processes:
|
||||
|
||||
process2:
|
||||
command: "echo process2"
|
||||
availability:
|
||||
restart: "on_failure"
|
||||
depends_on:
|
||||
process3:
|
||||
process1:
|
||||
condition: process_completed_successfully
|
||||
|
||||
process3:
|
||||
command: "echo process3"
|
||||
availability:
|
||||
restart: "on_failure"
|
||||
backoff_seconds: 2
|
||||
# depends_on:
|
||||
# process1:
|
||||
# condition: process_completed_successfully
|
||||
depends_on:
|
||||
process1:
|
||||
condition: process_completed_successfully
|
||||
|
||||
|
11
fixtures-code/process-compose-non-circular.yaml
Normal file
11
fixtures-code/process-compose-non-circular.yaml
Normal file
@ -0,0 +1,11 @@
|
||||
version: "0.5"
|
||||
processes:
|
||||
process1:
|
||||
command: "echo process1"
|
||||
|
||||
process3:
|
||||
command: "echo process3"
|
||||
depends_on:
|
||||
process1:
|
||||
condition: process_completed_successfully
|
||||
|
@ -130,28 +130,27 @@ func TestSystem_TestComposeChainExit(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
//func TestSystem_TestComposeCircular(t *testing.T) {
|
||||
// fixture := filepath.Join("..", "..", "fixtures", "process-compose-circular.yaml")
|
||||
// t.Run(fixture, func(t *testing.T) {
|
||||
// project, err := loader.Load(&loader.LoaderOptions{
|
||||
// FileNames: []string{fixture},
|
||||
// })
|
||||
// if err != nil {
|
||||
// t.Errorf(err.Error())
|
||||
// return
|
||||
// }
|
||||
// runner, err := NewProjectRunner(project, []string{}, false)
|
||||
// if err != nil {
|
||||
// t.Errorf(err.Error())
|
||||
// return
|
||||
// }
|
||||
// exitCode := runner.Run()
|
||||
// want := 42
|
||||
// if want != exitCode {
|
||||
// t.Errorf("Project.Run() = %v, want %v", exitCode, want)
|
||||
// }
|
||||
// })
|
||||
//}
|
||||
func TestSystem_TestComposeCircular(t *testing.T) {
|
||||
fixture1 := filepath.Join("..", "..", "fixtures-code", "process-compose-circular.yaml")
|
||||
fixture2 := filepath.Join("..", "..", "fixtures-code", "process-compose-non-circular.yaml")
|
||||
t.Run(fixture1, func(t *testing.T) {
|
||||
_, err := loader.Load(&loader.LoaderOptions{
|
||||
FileNames: []string{fixture1},
|
||||
})
|
||||
if err == nil {
|
||||
t.Errorf("should fail on cirlcular dependency")
|
||||
return
|
||||
}
|
||||
|
||||
_, err = loader.Load(&loader.LoaderOptions{
|
||||
FileNames: []string{fixture2},
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSystem_TestComposeScale(t *testing.T) {
|
||||
fixture := filepath.Join("..", "..", "fixtures-code", "process-compose-scale.yaml")
|
||||
|
@ -27,7 +27,7 @@ func Load(opts *LoaderOptions) (*types.Project, error) {
|
||||
opts.projects = append(opts.projects, p)
|
||||
}
|
||||
mergedProject, err := merge(opts)
|
||||
mergedProject.ValidateAfterMerge()
|
||||
err = mergedProject.ValidateAfterMerge()
|
||||
return mergedProject, err
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/f1bonacc1/process-compose/src/command"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
@ -14,9 +15,10 @@ func (p *Project) Validate() {
|
||||
p.validateProcessConfig()
|
||||
}
|
||||
|
||||
func (p *Project) ValidateAfterMerge() {
|
||||
func (p *Project) ValidateAfterMerge() error {
|
||||
p.assignDefaultProcessValues()
|
||||
p.cloneReplicas()
|
||||
return p.validateNoCircularDependencies()
|
||||
}
|
||||
|
||||
func (p *Project) validateLogLevel() {
|
||||
@ -100,3 +102,41 @@ func (p *Project) cloneReplicas() {
|
||||
p.Processes[proc.ReplicaName] = proc
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Project) validateNoCircularDependencies() error {
|
||||
visited := make(map[string]bool, len(p.Processes))
|
||||
stack := make(map[string]bool)
|
||||
for name := range p.Processes {
|
||||
if !visited[name] {
|
||||
if p.isCyclicHelper(name, visited, stack) {
|
||||
return fmt.Errorf("circular dependency found in %s", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) isCyclicHelper(procName string, visited map[string]bool, stack map[string]bool) bool {
|
||||
visited[procName] = true
|
||||
stack[procName] = true
|
||||
|
||||
processes, err := p.getProcesses(procName)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, process := range processes {
|
||||
dependencies := process.GetDependencies()
|
||||
for _, neighbor := range dependencies {
|
||||
if !visited[neighbor] {
|
||||
if p.isCyclicHelper(neighbor, visited, stack) {
|
||||
return true
|
||||
}
|
||||
} else if stack[neighbor] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stack[procName] = false
|
||||
return false
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user