diff --git a/service_upstart_linux.go b/service_upstart_linux.go index 6715955..9ce441e 100644 --- a/service_upstart_linux.go +++ b/service_upstart_linux.go @@ -11,7 +11,6 @@ import ( "os/exec" "os/signal" "regexp" - "strconv" "strings" "text/template" "time" @@ -108,24 +107,7 @@ func (s *upstart) getUpstartVersion() []int { return nil } - version := make([]int, 3) - for idx, vStr := range strings.Split(matches[1], ".") { - version[idx], err = strconv.Atoi(vStr) - if err != nil { - return nil - } - } - return version -} - -func versionAtMost(version, max []int) bool { - for idx, m := range max { - v := version[idx] - if v > m { - return false - } - } - return true + return parseVersion(matches[1]) } func (s *upstart) template() *template.Template { @@ -167,6 +149,10 @@ func (s *upstart) Install() error { s.Option.bool(optionLogOutput, optionLogOutputDefault), } + fmt.Printf("upstarts supports kill stanza: %t\n", to.HasKillStanza) + fmt.Printf("upstarts supports setuid stanza: %t\n", to.HasSetUIDStanza) + fmt.Printf("log output to files: %t\n", to.LogOutput) + return s.template().Execute(f, to) } diff --git a/version.go b/version.go new file mode 100644 index 0000000..9d40c98 --- /dev/null +++ b/version.go @@ -0,0 +1,57 @@ +package service + +import ( + "errors" + "strconv" + "strings" +) + +// versionAtMost will return true if the provided version is less than or equal to max +func versionAtMost(version, max []int) (bool, error) { + if comp, err := versionCompare(version, max); err != nil { + return false, err + } else if comp == 1 { + return false, nil + } + return true, nil +} + +// versionCompare take to versions split into integer arrays and attempts to compare them +// An error will be returned if there is an array length mismatch. +// Return values are as follows +// -1 - v1 is less than v2 +// 0 - v1 is equal to v2 +// 1 - v1 is greater than v2 +func versionCompare(v1, v2 []int) (int, error) { + if len(v1) != len(v2) { + return 0, errors.New("version length mismatch") + } + + for idx, v2S := range v2 { + v1S := v1[idx] + if v1S > v2S { + return 1, nil + } + + if v1S < v2S { + return -1, nil + } + } + return 0, nil +} + +// parseVersion will parse any integer type version seperated by periods. +// This does not fully support semver style versions. +func parseVersion(v string) []int { + version := make([]int, 3) + + for idx, vStr := range strings.Split(v, ".") { + vS, err := strconv.Atoi(vStr) + if err != nil { + return nil + } + version[idx] = vS + } + + return version +} diff --git a/version_test.go b/version_test.go new file mode 100644 index 0000000..90bbd82 --- /dev/null +++ b/version_test.go @@ -0,0 +1,106 @@ +package service + +import ( + "reflect" + "testing" +) + +func Test_versionCompare(t *testing.T) { + type args struct { + v1 []int + v2 []int + } + tests := []struct { + name string + args args + want int + wantErr bool + }{ + {"segment-mismatch-1", args{[]int{0, 0, 0, 0}, []int{0, 0, 0}}, 0, true}, + {"segment-mismatch-2", args{[]int{0, 0, 0}, []int{0, 0, 0, 0}}, 0, true}, + {"equal-to-1", args{[]int{0, 0, 0}, []int{0, 0, 0}}, 0, false}, + {"equal-to-2", args{[]int{0, 0, 1}, []int{0, 0, 1}}, 0, false}, + {"equal-to-3", args{[]int{0, 1, 0}, []int{0, 1, 0}}, 0, false}, + {"equal-to-4", args{[]int{1, 0, 0}, []int{1, 0, 0}}, 0, false}, + {"equal-to-5", args{[]int{2, 2, 2}, []int{2, 2, 2}}, 0, false}, + {"less-than-1", args{[]int{0, 0, 0}, []int{0, 0, 1}}, -1, false}, + {"less-than-2", args{[]int{0, 0, 1}, []int{0, 1, 0}}, -1, false}, + {"less-than-3", args{[]int{0, 1, 0}, []int{1, 0, 0}}, -1, false}, + {"less-than-4", args{[]int{0, 1, 0}, []int{1, 0, 0}}, -1, false}, + {"less-than-5", args{[]int{0, 8, 0}, []int{1, 5, 0}}, -1, false}, + {"greater-than-1", args{[]int{0, 0, 1}, []int{0, 0, 0}}, 1, false}, + {"greater-than-2", args{[]int{0, 1, 0}, []int{0, 0, 1}}, 1, false}, + {"greater-than-3", args{[]int{1, 0, 0}, []int{0, 1, 0}}, 1, false}, + {"greater-than-4", args{[]int{1, 0, 0}, []int{0, 1, 0}}, 1, false}, + {"greater-than-5", args{[]int{1, 5, 0}, []int{0, 8, 0}}, 1, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := versionCompare(tt.args.v1, tt.args.v2) + if (err != nil) != tt.wantErr { + t.Errorf("versionCompare() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("versionCompare() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_parseVersion(t *testing.T) { + type args struct { + v string + } + tests := []struct { + name string + args args + want []int + }{ + {"sanity-check", args{"0.0.0"}, []int{0, 0, 0}}, + {"should-fail", args{"0.zero.0"}, nil}, + {"should-fail-no-semver", args{"0.0.0-test+1"}, nil}, + {"double-digits", args{"5.200.1"}, []int{5, 200, 1}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := parseVersion(tt.args.v); !reflect.DeepEqual(got, tt.want) { + t.Errorf("parseVersion() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_versionAtMost(t *testing.T) { + type args struct { + version []int + max []int + } + tests := []struct { + name string + args args + want bool + wantErr bool + }{ + {"segment-mismatch-1", args{[]int{0, 0, 0, 0}, []int{0, 0, 0}}, false, true}, + {"segment-mismatch-2", args{[]int{0, 0, 0}, []int{0, 0, 0, 0}}, false, true}, + {"test-1", args{[]int{0, 0, 0}, []int{0, 0, 1}}, true, false}, + {"test-2", args{[]int{0, 1, 0}, []int{0, 1, 0}}, true, false}, + {"test-3", args{[]int{1, 0, 0}, []int{1, 0, 0}}, true, false}, + {"negative-test-1", args{[]int{0, 0, 1}, []int{0, 0, 0}}, false, false}, + {"negative-test-2", args{[]int{0, 1, 0}, []int{0, 0, 1}}, false, false}, + {"negative-test-3", args{[]int{1, 0, 0}, []int{0, 1, 0}}, false, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := versionAtMost(tt.args.version, tt.args.max) + if (err != nil) != tt.wantErr { + t.Errorf("versionAtMost() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("versionAtMost() = %v, want %v", got, tt.want) + } + }) + } +}