// Copyright 2023 Harness, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package dag import ( "reflect" "testing" ) func TestDag(t *testing.T) { dag := New() dag.Add("backend") dag.Add("frontend") dag.Add("notify", "backend", "frontend") if dag.DetectCycles() { t.Errorf("cycles detected") } dag = New() dag.Add("notify", "backend", "frontend") if dag.DetectCycles() { t.Errorf("cycles detected") } dag = New() dag.Add("backend", "frontend") dag.Add("frontend", "backend") dag.Add("notify", "backend", "frontend") if dag.DetectCycles() == false { t.Errorf("Expect cycles detected") } dag = New() dag.Add("backend", "backend") dag.Add("frontend", "backend") dag.Add("notify", "backend", "frontend") if dag.DetectCycles() == false { t.Errorf("Expect cycles detected") } dag = New() dag.Add("backend") dag.Add("frontend") dag.Add("notify", "backend", "frontend", "notify") if dag.DetectCycles() == false { t.Errorf("Expect cycles detected") } } func TestAncestors(t *testing.T) { dag := New() v := dag.Add("backend") dag.Add("frontend", "backend") dag.Add("notify", "frontend") ancestors := dag.Ancestors("frontend") if got, want := len(ancestors), 1; got != want { t.Errorf("Want %d ancestors, got %d", want, got) } if ancestors[0] != v { t.Errorf("Unexpected ancestor") } if v := dag.Ancestors("backend"); len(v) != 0 { t.Errorf("Expect vertexes with no dependencies has zero ancestors") } } func TestAncestors_Skipped(t *testing.T) { dag := New() dag.Add("backend").Skip = true dag.Add("frontend", "backend").Skip = true dag.Add("notify", "frontend") if v := dag.Ancestors("frontend"); len(v) != 0 { t.Errorf("Expect skipped vertexes excluded") } if v := dag.Ancestors("notify"); len(v) != 0 { t.Errorf("Expect skipped vertexes excluded") } } func TestAncestors_NotFound(t *testing.T) { dag := New() dag.Add("backend") dag.Add("frontend", "backend") dag.Add("notify", "frontend") if dag.DetectCycles() { t.Errorf("cycles detected") } if v := dag.Ancestors("does-not-exist"); len(v) != 0 { t.Errorf("Expect vertex not found does not panic") } } func TestAncestors_Malformed(t *testing.T) { dag := New() dag.Add("backend") dag.Add("frontend", "does-not-exist") dag.Add("notify", "frontend") if dag.DetectCycles() { t.Errorf("cycles detected") } if v := dag.Ancestors("frontend"); len(v) != 0 { t.Errorf("Expect invalid dependency does not panic") } } func TestAncestors_Complex(t *testing.T) { dag := New() dag.Add("backend") dag.Add("frontend") dag.Add("publish", "backend", "frontend") dag.Add("deploy", "publish") last := dag.Add("notify", "deploy") if dag.DetectCycles() { t.Errorf("cycles detected") } ancestors := dag.Ancestors("notify") if got, want := len(ancestors), 4; got != want { t.Errorf("Want %d ancestors, got %d", want, got) return } for _, ancestor := range ancestors { if ancestor == last { t.Errorf("Unexpected ancestor") } } v, _ := dag.Get("publish") v.Skip = true ancestors = dag.Ancestors("notify") if got, want := len(ancestors), 3; got != want { t.Errorf("Want %d ancestors, got %d", want, got) return } } func TestDependencies(t *testing.T) { dag := New() dag.Add("backend") dag.Add("frontend") dag.Add("publish", "backend", "frontend") if deps := dag.Dependencies("backend"); len(deps) != 0 { t.Errorf("Expect zero dependencies") } if deps := dag.Dependencies("frontend"); len(deps) != 0 { t.Errorf("Expect zero dependencies") } got, want := dag.Dependencies("publish"), []string{"backend", "frontend"} if !reflect.DeepEqual(got, want) { t.Errorf("Unexpected dependencies, got %v", got) } } func TestDependencies_Skipped(t *testing.T) { dag := New() dag.Add("backend") dag.Add("frontend").Skip = true dag.Add("publish", "backend", "frontend") if deps := dag.Dependencies("backend"); len(deps) != 0 { t.Errorf("Expect zero dependencies") } if deps := dag.Dependencies("frontend"); len(deps) != 0 { t.Errorf("Expect zero dependencies") } got, want := dag.Dependencies("publish"), []string{"backend"} if !reflect.DeepEqual(got, want) { t.Errorf("Unexpected dependencies, got %v", got) } } func TestDependencies_Complex(t *testing.T) { dag := New() dag.Add("clone") dag.Add("backend") dag.Add("frontend", "backend").Skip = true dag.Add("publish", "frontend", "clone") dag.Add("notify", "publish") if deps := dag.Dependencies("clone"); len(deps) != 0 { t.Errorf("Expect zero dependencies for clone") } if deps := dag.Dependencies("backend"); len(deps) != 0 { t.Errorf("Expect zero dependencies for backend") } got, want := dag.Dependencies("frontend"), []string{"backend"} if !reflect.DeepEqual(got, want) { t.Errorf("Unexpected dependencies for frontend, got %v", got) } got, want = dag.Dependencies("publish"), []string{"backend", "clone"} if !reflect.DeepEqual(got, want) { t.Errorf("Unexpected dependencies for publish, got %v", got) } got, want = dag.Dependencies("notify"), []string{"publish"} if !reflect.DeepEqual(got, want) { t.Errorf("Unexpected dependencies for notify, got %v", got) } }