blob: c2e635e4af2258848a9ebe0db5001c19540753a8 [file] [edit]
// Copyright 2019 Google Inc. All Rights Reserved.
//
// 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 osinfo
import (
"context"
"os"
"path/filepath"
"testing"
"github.com/google/go-cmp/cmp"
"golang.org/x/sys/unix"
)
var debianReleaseFileContent = `PRETTY_NAME="Debian buster"
NAME="Debian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
`
func TestLinuxOsInfoProvider(t *testing.T) {
stubProvider := func() (string, string, string) {
return "testShort", "testLong", "testVersion"
}
tests := []struct {
name string
uts unix.Utsname
nameVersionProvider func() (string, string, string)
want OSInfo
}{
{
name: "debian system",
uts: unix.Utsname{
Nodename: toUtsField("testhost"),
Machine: toUtsField("amd64"),
Release: toUtsField("6.1.0-29-cloud-amd64"),
Version: toUtsField("#1 SMP PREEMPT_DYNAMIC Debian 6.1.123-1 (2025-01-02)"),
},
nameVersionProvider: stubProvider,
want: OSInfo{
Hostname: "testhost",
LongName: "testLong",
ShortName: "testShort",
Version: "testVersion",
KernelVersion: "#1 SMP PREEMPT_DYNAMIC Debian 6.1.123-1 (2025-01-02)",
KernelRelease: "6.1.0-29-cloud-amd64",
Architecture: "x86_64",
},
},
{
name: "ubuntu system",
uts: unix.Utsname{
Nodename: toUtsField("testhost"),
Machine: toUtsField("i386"),
Release: toUtsField("6.1.0-29-cloud-i386"),
Version: toUtsField("#17~22.04.1-Ubuntu SMP Tue Sep 3 16:11:52 UTC 2024"),
},
nameVersionProvider: stubProvider,
want: OSInfo{
Hostname: "testhost",
LongName: "testLong",
ShortName: "testShort",
Version: "testVersion",
KernelVersion: "#17~22.04.1-Ubuntu SMP Tue Sep 3 16:11:52 UTC 2024",
KernelRelease: "6.1.0-29-cloud-i386",
Architecture: "x86_32",
},
},
{
name: "ubuntu system noarch",
uts: unix.Utsname{
Nodename: toUtsField("testhost"),
Machine: toUtsField("noarch"),
Release: toUtsField("6.1.0-29-cloud"),
Version: toUtsField("#17~22.04.1-Ubuntu SMP Tue Sep 3 16:11:52 UTC 2024"),
},
nameVersionProvider: stubProvider,
want: OSInfo{
Hostname: "testhost",
LongName: "testLong",
ShortName: "testShort",
Version: "testVersion",
KernelVersion: "#17~22.04.1-Ubuntu SMP Tue Sep 3 16:11:52 UTC 2024",
KernelRelease: "6.1.0-29-cloud",
Architecture: "all",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
linuxOsinfoProvider := LinuxOsInfoProvider{
nameAndVersionProvider: tt.nameVersionProvider,
uts: tt.uts,
}
ctx := context.Background()
got, err := linuxOsinfoProvider.GetOSInfo(ctx)
if err != nil {
t.Errorf("Unexpected error, err: %v", err)
}
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("Unexpected OsInfo (-want,+got):\n%s", diff)
}
})
}
}
func Test_parseOsRelease(t *testing.T) {
tests := []struct {
name string
input string
expectedShortName string
expectedLongName string
expectedVersion string
}{
{
name: "Empty content",
input: ``,
expectedShortName: "linux",
expectedLongName: "",
expectedVersion: "",
},
{
name: "Empty key",
input: `=`,
expectedShortName: "linux",
expectedLongName: "",
expectedVersion: "",
},
{
name: "Debian 10, normal case",
input: debianReleaseFileContent,
expectedShortName: "debian",
expectedLongName: "Debian buster",
expectedVersion: "10",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
shortName, longName, version := parseOsRelease(tt.input)
if tt.expectedShortName != shortName {
t.Errorf("Unexpected shortName, expected %q, got %q", tt.expectedShortName, shortName)
}
if tt.expectedLongName != longName {
t.Errorf("Unexpected longName, expected %q, got %q", tt.expectedLongName, longName)
}
if tt.expectedVersion != version {
t.Errorf("Unexpected version, expected %q, got %q", tt.expectedVersion, version)
}
})
}
}
func Test_parseEnterpriseRelease(t *testing.T) {
tests := []struct {
name string
input string
expectedShortName string
expectedLongName string
expectedVersion string
}{
{
name: "Empty content",
input: ``,
expectedShortName: "linux",
expectedLongName: "",
expectedVersion: "",
},
{
name: "Red Hat Enterprise, normal case",
input: `Red Hat Enterprise Linux release 8.0 (Ootpa)`,
expectedShortName: "rhel",
expectedLongName: "Red Hat Enterprise Linux 8.0 (Ootpa)",
expectedVersion: "8.0",
},
{
name: "CentOS Linux, normal case",
input: `CentOS Linux release 7.6.1810 (Core)`,
expectedShortName: "centos",
expectedLongName: "CentOS Linux 7.6.1810 (Core)",
expectedVersion: "7.6.1810",
},
{
name: "Oracle Linux Server, normal case",
input: `Oracle Linux Server release 9.5`,
expectedShortName: "ol",
expectedLongName: "Oracle Linux Server 9.5",
expectedVersion: "9.5",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
shortName, longName, version := parseEnterpriseRelease(tt.input)
if tt.expectedShortName != shortName {
t.Errorf("Unexpected shortName, expected %q, got %q", tt.expectedShortName, shortName)
}
if tt.expectedLongName != longName {
t.Errorf("Unexpected longName, expected %q, got %q", tt.expectedLongName, longName)
}
if tt.expectedVersion != version {
t.Errorf("Unexpected version, expected %q, got %q", tt.expectedVersion, version)
}
})
}
}
func Test_osNameAndVersionProvider(t *testing.T) {
tests := []struct {
name string
enforceTestingEnvironment func(t *testing.T)
expectedShortName string
expectedLongName string
expectedVersion string
}{
{
name: "no file exists",
enforceTestingEnvironment: func(t *testing.T) {
doesNotExists := filepath.Join(os.TempDir(), "does_not_exists")
overrideDefaultReleaseFilepath(t, doesNotExists)
overrideOracleReleaseFilepath(t, doesNotExists)
overrideRedHatReleaseFilepath(t, doesNotExists)
},
expectedShortName: "linux",
expectedLongName: "",
expectedVersion: "",
},
{
name: "default release file exists, but empty",
enforceTestingEnvironment: func(t *testing.T) {
doesNotExists := filepath.Join(os.TempDir(), "does_not_exists")
defaultReleaseFile := filepath.Join(os.TempDir(), "default_release_file")
enforceFileWithContent(t, defaultReleaseFile, []byte(""))
overrideDefaultReleaseFilepath(t, defaultReleaseFile)
overrideOracleReleaseFilepath(t, doesNotExists)
overrideRedHatReleaseFilepath(t, doesNotExists)
},
expectedShortName: "linux",
expectedLongName: "",
expectedVersion: "",
},
{
name: "default release path exists, but it not a file",
enforceTestingEnvironment: func(t *testing.T) {
tmpDir := os.TempDir()
doesNotExists := filepath.Join(os.TempDir(), "does_not_exists")
overrideDefaultReleaseFilepath(t, tmpDir)
overrideOracleReleaseFilepath(t, doesNotExists)
overrideRedHatReleaseFilepath(t, doesNotExists)
},
expectedShortName: "linux",
expectedLongName: "",
expectedVersion: "",
},
{
name: "Debian release file exists",
enforceTestingEnvironment: func(t *testing.T) {
doesNotExists := filepath.Join(os.TempDir(), "does_not_exists")
debianReleaseFile := filepath.Join(os.TempDir(), "debian_release_file")
enforceFileWithContent(t, debianReleaseFile, []byte(debianReleaseFileContent))
overrideDefaultReleaseFilepath(t, debianReleaseFile)
overrideOracleReleaseFilepath(t, doesNotExists)
overrideRedHatReleaseFilepath(t, doesNotExists)
},
expectedShortName: "debian",
expectedLongName: "Debian buster",
expectedVersion: "10",
},
{
name: "Oracle Linux release file exists",
enforceTestingEnvironment: func(t *testing.T) {
doesNotExists := filepath.Join(os.TempDir(), "does_not_exists")
oracleReleaseFile := filepath.Join(os.TempDir(), "oracle_release_file")
oracleReleaseFileContent := `Oracle Linux Server release 9.5`
enforceFileWithContent(t, oracleReleaseFile, []byte(oracleReleaseFileContent))
overrideDefaultReleaseFilepath(t, doesNotExists)
overrideOracleReleaseFilepath(t, oracleReleaseFile)
overrideRedHatReleaseFilepath(t, doesNotExists)
},
expectedShortName: "ol",
expectedLongName: "Oracle Linux Server 9.5",
expectedVersion: "9.5",
},
{
name: "Red Hat release file exists",
enforceTestingEnvironment: func(t *testing.T) {
doesNotExists := filepath.Join(os.TempDir(), "does_not_exists")
redHatReleaseFile := filepath.Join(os.TempDir(), "redhat_release_file")
redHatReleaseFileContent := `Red Hat Enterprise Linux release 8.0 (Ootpa)`
enforceFileWithContent(t, redHatReleaseFile, []byte(redHatReleaseFileContent))
overrideDefaultReleaseFilepath(t, doesNotExists)
overrideOracleReleaseFilepath(t, doesNotExists)
overrideRedHatReleaseFilepath(t, redHatReleaseFile)
},
expectedShortName: "rhel",
expectedLongName: "Red Hat Enterprise Linux 8.0 (Ootpa)",
expectedVersion: "8.0",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.enforceTestingEnvironment(t)
osNameAndVersionProvider := getOsNameAndVersionProvider(context.Background())
shortName, longName, version := osNameAndVersionProvider()
if tt.expectedShortName != shortName {
t.Errorf("unexpected value of \"shortName\", expected %q, got %q", tt.expectedShortName, shortName)
}
if tt.expectedLongName != longName {
t.Errorf("unexpected value of \"longName\", expected %q, got %q", tt.expectedLongName, longName)
}
if tt.expectedVersion != version {
t.Errorf("unexpected value of \"version\", expected %q, got %q", tt.expectedVersion, version)
}
})
}
}
func toUtsField(val string) [65]byte {
var result [65]byte
for i := 0; i < len(val); i++ {
result[i] = val[i]
}
result[len(val)] = '\x00'
return result
}
func TestNewLinuxOsInfoProvider(t *testing.T) {
ctx := context.Background()
osInfoProvider, err := NewLinuxOsInfoProvider(getOsNameAndVersionProvider(ctx))
if err != nil {
t.Errorf("unable to create osInfoProvider, err: %v", err)
return
}
if osInfoProvider == nil {
t.Errorf("expected fully functional os info provider, but get nil")
}
}
func overrideDefaultReleaseFilepath(t *testing.T, filepath string) {
prev := defaultReleaseFilepath
defaultReleaseFilepath = filepath
t.Cleanup(func() {
defaultReleaseFilepath = prev
})
}
func overrideOracleReleaseFilepath(t *testing.T, filepath string) {
prev := oracleReleaseFilepath
oracleReleaseFilepath = filepath
t.Cleanup(func() {
oracleReleaseFilepath = prev
})
}
func overrideRedHatReleaseFilepath(t *testing.T, filepath string) {
prev := redHatReleaseFilepath
redHatReleaseFilepath = filepath
t.Cleanup(func() {
redHatReleaseFilepath = prev
})
}
func enforceFileWithContent(t *testing.T, filepath string, content []byte) {
if err := os.WriteFile(filepath, content, 0644); err != nil {
t.Errorf("unexpected error while enforcing file content, err: %v", err)
}
}