blob: ab7a995fbbfb4116cdd6ba0603ddd352ba368d11 [file] [log] [blame]
package binary
import (
"testing"
"cos.googlesource.com/cos/tools/src/cmd/cos_image_analyzer/internal/input"
"cos.googlesource.com/cos/tools/src/cmd/cos_image_analyzer/internal/utilities"
)
// test Diff function
func TestDiff(t *testing.T) {
testCompressRootfsSlice := []string{"/proc/", "/usr/lib/", "/util/", "/etc/os-release/", "/etc/sysctl.d/"}
testCompressStatefulSlice := []string{"/var_overlay/"}
// Rootfs test data
testVerboseRootfsDiff := `Files ../testdata/image1/rootfs/lib64/python.txt and ../testdata/image2/rootfs/lib64/python.txt differ
Files ../testdata/image1/rootfs/proc/security/access.conf and ../testdata/image2/rootfs/proc/security/access.conf differ
Files ../testdata/image1/rootfs/proc/security/configs and ../testdata/image2/rootfs/proc/security/configs differ
Only in ../testdata/image1/rootfs/usr/lib: usr-lib-image1
Only in ../testdata/image2/rootfs/usr/lib: usr-lib-image2`
testBriefRootfsDiff := `Files ../testdata/image1/rootfs/lib64/python.txt and ../testdata/image2/rootfs/lib64/python.txt differ
Files in ../testdata/image1/rootfs/proc and ../testdata/image2/rootfs/proc differ
Unique files in ../testdata/image1/rootfs/usr/lib
Unique files in ../testdata/image2/rootfs/usr/lib`
// OS Config test data
testVerboseOSConfig := map[string]string{
"/etc/docker/": `Configs for directory /etc/docker/
diff -r --no-dereference ../testdata/image1/rootfs/etc/docker/credentials.txt ../testdata/image2/rootfs/etc/docker/credentials.txt
1,2c1,2
< Name: docker.10.2.4
< job: makes micro kernels
\ No newline at end of file
---
> Name: docker.10.2.1
> job: makes macro kernels
\ No newline at end of file
Only in ../testdata/image1/rootfs/etc/docker/util: docker.txt
Only in ../testdata/image1/rootfs/etc/docker/util: lib32
Only in ../testdata/image2/rootfs/etc/docker/util: lib64`,
"/etc/os-release/": `Configs for file /etc/os-release/
1c1
< BUILD_ID=12871.119.0
---
> BUILD_ID=12371.273.0
3c3
< KERNEL_COMMIT_ID=fa84f12c6d738af9486e69a006a57df923f9476a
---
> KERNEL_COMMIT_ID=5d4ffd91281840f7a118143d77fbefb02e87943c
5c5
< VERSION_ID=81
---
> VERSION_ID=77
8c8
< VERSION=81
---
> VERSION=77`,
"/etc/sysctl.d/": `Configs for directory /etc/sysctl.d/
diff -r --no-dereference ../testdata/image1/rootfs/etc/sysctl.d/00-sysctl.conf ../testdata/image2/rootfs/etc/sysctl.d/00-sysctl.conf
8c8
< net.ipv4.conf.all.rp_filter = 1
---
> net.ipv4.conf.all.rp_filter = 2
11c11,14
< net.ipv4.tcp_slow_start_after_idle = 0
\ No newline at end of file
---
> net.ipv4.tcp_slow_start_after_idle = 1
>
> # dumby variable
> net.ipv4.conf = 2
\ No newline at end of file`}
testBriefOSConfig := map[string]string{
"/etc/docker/": `Configs for directory /etc/docker/
diff -r --no-dereference ../testdata/image1/rootfs/etc/docker/credentials.txt ../testdata/image2/rootfs/etc/docker/credentials.txt
1,2c1,2
< Name: docker.10.2.4
< job: makes micro kernels
\ No newline at end of file
---
> Name: docker.10.2.1
> job: makes macro kernels
\ No newline at end of file
Only in ../testdata/image1/rootfs/etc/docker/util: docker.txt
Only in ../testdata/image1/rootfs/etc/docker/util: lib32
Only in ../testdata/image2/rootfs/etc/docker/util: lib64`}
// Stateful test data
testVerboseStatefulDiff := `Only in ../testdata/image1/stateful/dev_image: image1_dev.txt
Only in ../testdata/image2/stateful/dev_image: image2_dev.txt
Only in ../testdata/image1/stateful/var_overlay/db: image1_data.txt
Only in ../testdata/image2/stateful/var_overlay/db: image2_data.txt`
testBriefStatefulDiff := `Only in ../testdata/image1/stateful/dev_image: image1_dev.txt
Only in ../testdata/image2/stateful/dev_image: image2_dev.txt
Unique files in ../testdata/image1/stateful/var_overlay
Unique files in ../testdata/image2/stateful/var_overlay`
// Partition Structure data
testPartitionStructure := `1c1
< Disk /img_disks/cos_81_12871_119_disk/disk.raw: 20971520 sectors, 10.0 GiB
---
> Disk /img_disks/cos_77_12371_273_disk/disk.raw: 20971520 sectors, 10.0 GiB
3c3
< Disk identifier (GUID): 0274E604-5DE3-5E4E-A4FD-F4D00FBBD7AA
---
> Disk identifier (GUID): AB9719F2-3174-4F46-8079-1CF470D2D9BC
11c11
< 1 8704000 18874476 4.8 GiB 8300 STATE
---
> 1 8704000 18874476 4.8 GiB 0700 STATE
18c18
< 8 86016 118783 16.0 MiB 8300 OEM
---
> 8 86016 118783 16.0 MiB 0700 OEM`
// Kernel configs data
testKernelConfigsImage1 := `#
# Compiler: Chromium OS 10.0_pre377782_p20200113-r10 clang version 10.0.0 (/var/cache/chromeos-cache/distfiles/host/egit-src/llvm-project 4e8231b5cf0f5f62c7a51a857e29f5be5cb55734)
#
CONFIG_GCC_VERSION=0
CONFIG_CC_IS_CLANG=y
CONFIG_CLANG_VERSION=100000
#
# General setup
#
CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_LOCALVERSION=""
CONFIG_BUILD_SALT=""
CONFIG_HAVE_KERNEL_GZIP=y`
testKernelConfigsDiff := `2c2
< # Compiler: Chromium OS 10.0_pre377782_p20200113-r10 clang version 10.0.0 (/var/cache/chromeos-cache/distfiles/host/egit-src/llvm-project 4e8231b5cf0f5f62c7a51a857e29f5be5cb55734)
---
> # Compiler: Chromium OS 9.0_pre361749_p20190714-r4 clang version 9.0.0 (/var/cache/chromeos-cache/distfiles/host/egit-src/llvm-project c11de5eada2decd0a495ea02676b6f4838cd54fb) (based on LLVM 9.0.0svn)
6c6
< CONFIG_CLANG_VERSION=100000
---
> CONFIG_CLANG_VERSION=90000
11a12
> # CONFIG_COMPILE_TEST is not set
12a14
> # CONFIG_LOCALVERSION_AUTO is not set
14c16
< CONFIG_HAVE_KERNEL_GZIP=y
\ No newline at end of file
---
> CONFIG_HAVE_KERNEL_GZIP=y`
// Kernel Command Line data
kclImage1 := `linux /syslinux/vmlinuz.A init=/usr/lib/systemd/systemd boot=local rootwait ro dm_verity.dev_wait=50`
kclImage2 := `linux /syslinux/vmlinuz.A init=/usr/lib32/systemd/ ro dm_verity.dev_wait=1 i915.modeset=1 cros_efi`
testKCLImage1 := map[string]string{"Image1 KCL": kclImage1}
testKCLDiff := map[string]string{
"boot": `d
< boot=local`,
"cros_efi": `a
> cros_efi`,
"dm_verity.dev_wait": `c
< dm_verity.dev_wait=50
---
> dm_verity.dev_wait=1`,
"i915.modeset": `a
> i915.modeset=1`,
"init": `c
< init=/usr/lib/systemd/systemd
---
> init=/usr/lib32/systemd/`,
"rootwait": `d
< rootwait`}
// Sysctl settings
testSysctlSettingsImage1 := `# /etc/sysctl.conf
# Look in /proc/sys/ for all the things you can setup.
#
# Enables source route verification
net.ipv4.conf.default.rp_filter = 1
# Enable reverse path
net.ipv4.conf.all.rp_filter = 1
# Disable shrinking the cwnd when connection is idle
net.ipv4.tcp_slow_start_after_idle = 0`
testSysctlSettingsDiff := `8c8
< net.ipv4.conf.all.rp_filter = 1
---
> net.ipv4.conf.all.rp_filter = 2
11c11,14
< net.ipv4.tcp_slow_start_after_idle = 0
\ No newline at end of file
---
> net.ipv4.tcp_slow_start_after_idle = 1
>
> # dumby variable
> net.ipv4.conf = 2
\ No newline at end of file`
for _, tc := range []struct {
Image1 *input.ImageInfo
Image2 *input.ImageInfo
FlagInfo *input.FlagInfo
want *Differences
}{ // Version and BuildID difference tests
{Image1: &input.ImageInfo{RootfsPartition3: "../testdata/image1/rootfs/", Version: "81", BuildID: "12871.119.0"},
Image2: &input.ImageInfo{},
FlagInfo: &input.FlagInfo{BinaryTypesSelected: []string{"Version", "BuildID"}},
want: &Differences{Version: []string{"81", ""}, BuildID: []string{"12871.119.0", ""}}},
{Image1: &input.ImageInfo{RootfsPartition3: "../testdata/image1/rootfs/", Version: "81", BuildID: "12871.119.0"},
Image2: &input.ImageInfo{RootfsPartition3: "../testdata/image2/rootfs/", Version: "77", BuildID: "12371.273.0"},
FlagInfo: &input.FlagInfo{BinaryTypesSelected: []string{"Version", "BuildID"}},
want: &Differences{Version: []string{"81", "77"}, BuildID: []string{"12871.119.0", "12371.273.0"}}},
{Image1: &input.ImageInfo{RootfsPartition3: "../testdata/image1/rootfs/", Version: "81", BuildID: "12871.119.0"},
Image2: &input.ImageInfo{RootfsPartition3: "../testdata/image1/rootfs/", Version: "81", BuildID: "12871.119.1"},
FlagInfo: &input.FlagInfo{BinaryTypesSelected: []string{"Version", "BuildID"}},
want: &Differences{Version: []string{}, BuildID: []string{"12871.119.0", "12871.119.1"}}},
{Image1: &input.ImageInfo{RootfsPartition3: "../testdata/image1/rootfs/", Version: "81", BuildID: "12871.119.0"},
Image2: &input.ImageInfo{RootfsPartition3: "../testdata/image1/rootfs/", Version: "81", BuildID: "12871.119.0"},
FlagInfo: &input.FlagInfo{BinaryTypesSelected: []string{"Version", "BuildID"}},
want: &Differences{}},
// Rootfs difference test
{Image1: &input.ImageInfo{TempDir: "../testdata/image1", RootfsPartition3: "../testdata/image1/rootfs/"},
Image2: &input.ImageInfo{},
FlagInfo: &input.FlagInfo{BinaryTypesSelected: []string{"Rootfs"}},
want: &Differences{}},
{Image1: &input.ImageInfo{TempDir: "../testdata/image1", RootfsPartition3: "../testdata/image1/rootfs/"},
Image2: &input.ImageInfo{TempDir: "../testdata/image2", RootfsPartition3: "../testdata/image2/rootfs/"},
FlagInfo: &input.FlagInfo{BinaryTypesSelected: []string{"Rootfs"}, Verbose: true, CompressRootfsSlice: testCompressRootfsSlice},
want: &Differences{Rootfs: testVerboseRootfsDiff}},
{Image1: &input.ImageInfo{TempDir: "../testdata/image1", RootfsPartition3: "../testdata/image1/rootfs/"},
Image2: &input.ImageInfo{TempDir: "../testdata/image2", RootfsPartition3: "../testdata/image2/rootfs/"},
FlagInfo: &input.FlagInfo{BinaryTypesSelected: []string{"Rootfs"}, Verbose: false, CompressRootfsSlice: testCompressRootfsSlice},
want: &Differences{Rootfs: testBriefRootfsDiff}},
// OS Config difference test
{Image1: &input.ImageInfo{TempDir: "../testdata/image1", RootfsPartition3: "../testdata/image1/rootfs/"},
Image2: &input.ImageInfo{},
FlagInfo: &input.FlagInfo{BinaryTypesSelected: []string{"OS-config"}},
want: &Differences{}},
{Image1: &input.ImageInfo{TempDir: "../testdata/image1", RootfsPartition3: "../testdata/image1/rootfs/"},
Image2: &input.ImageInfo{TempDir: "../testdata/image2", RootfsPartition3: "../testdata/image2/rootfs/"},
FlagInfo: &input.FlagInfo{BinaryTypesSelected: []string{"OS-config"}, Verbose: true, CompressRootfsSlice: testCompressRootfsSlice},
want: &Differences{OSConfigs: testVerboseOSConfig}},
{Image1: &input.ImageInfo{TempDir: "../testdata/image1", RootfsPartition3: "../testdata/image1/rootfs/"},
Image2: &input.ImageInfo{TempDir: "../testdata/image2", RootfsPartition3: "../testdata/image2/rootfs/"},
FlagInfo: &input.FlagInfo{BinaryTypesSelected: []string{"OS-config"}, Verbose: false, CompressRootfsSlice: testCompressRootfsSlice},
want: &Differences{OSConfigs: testBriefOSConfig}},
// Stateful difference test
{Image1: &input.ImageInfo{TempDir: "../testdata/image1", StatePartition1: "../testdata/image1/stateful/"},
Image2: &input.ImageInfo{},
FlagInfo: &input.FlagInfo{BinaryTypesSelected: []string{"Stateful-partition"}},
want: &Differences{}},
{Image1: &input.ImageInfo{TempDir: "../testdata/image1", StatePartition1: "../testdata/image1/stateful/"},
Image2: &input.ImageInfo{TempDir: "../testdata/image2", StatePartition1: "../testdata/image2/stateful/"},
FlagInfo: &input.FlagInfo{BinaryTypesSelected: []string{"Stateful-partition"}, Verbose: true, CompressStatefulSlice: testCompressStatefulSlice},
want: &Differences{Stateful: testVerboseStatefulDiff}},
{Image1: &input.ImageInfo{TempDir: "../testdata/image1", StatePartition1: "../testdata/image1/stateful/"},
Image2: &input.ImageInfo{TempDir: "../testdata/image2", StatePartition1: "../testdata/image2/stateful/"},
FlagInfo: &input.FlagInfo{BinaryTypesSelected: []string{"Stateful-partition"}, Verbose: false, CompressStatefulSlice: testCompressStatefulSlice},
want: &Differences{Stateful: testBriefStatefulDiff}},
// Partition Structure
{Image1: &input.ImageInfo{TempDir: "../testdata/image1", PartitionFile: "../testdata/image1/partitions.txt"},
Image2: &input.ImageInfo{TempDir: "../testdata/image2", PartitionFile: "../testdata/image2/partitions.txt"},
FlagInfo: &input.FlagInfo{BinaryTypesSelected: []string{"Partition-structure"}},
want: &Differences{PartitionStructure: testPartitionStructure}},
// Kernel Configs
{Image1: &input.ImageInfo{TempDir: "../testdata/image1", KernelConfigsFile: "../testdata/image1/usr/src/linux-headers-4.19.112+/.config"},
Image2: &input.ImageInfo{},
FlagInfo: &input.FlagInfo{BinaryTypesSelected: []string{"Kernel-configs"}},
want: &Differences{KernelConfigs: testKernelConfigsImage1}},
{Image1: &input.ImageInfo{TempDir: "../testdata/image1", KernelConfigsFile: "../testdata/image1/usr/src/linux-headers-4.19.112+/.config"},
Image2: &input.ImageInfo{TempDir: "../testdata/image2", KernelConfigsFile: "../testdata/image2/usr/src/linux-headers-4.19.112+/.config"},
FlagInfo: &input.FlagInfo{BinaryTypesSelected: []string{"Kernel-configs"}},
want: &Differences{KernelConfigs: testKernelConfigsDiff}},
// Kernel command line
{Image1: &input.ImageInfo{TempDir: "../testdata/image1", KernelCommandLine: kclImage1},
Image2: &input.ImageInfo{},
FlagInfo: &input.FlagInfo{BinaryTypesSelected: []string{"Kernel-command-line"}},
want: &Differences{KernelCommandLine: testKCLImage1}},
{Image1: &input.ImageInfo{TempDir: "../testdata/image1", KernelCommandLine: kclImage1},
Image2: &input.ImageInfo{TempDir: "../testdata/image2", KernelCommandLine: kclImage2},
FlagInfo: &input.FlagInfo{BinaryTypesSelected: []string{"Kernel-command-line"}},
want: &Differences{KernelCommandLine: testKCLDiff}},
// Sysctl settings
{Image1: &input.ImageInfo{TempDir: "../testdata/image1", SysctlSettingsFile: "../testdata/image1/rootfs/etc/sysctl.d/00-sysctl.conf"},
Image2: &input.ImageInfo{},
FlagInfo: &input.FlagInfo{BinaryTypesSelected: []string{"Sysctl-settings"}},
want: &Differences{SysctlSettings: testSysctlSettingsImage1}},
{Image1: &input.ImageInfo{TempDir: "../testdata/image1", SysctlSettingsFile: "../testdata/image1/rootfs/etc/sysctl.d/00-sysctl.conf"},
Image2: &input.ImageInfo{TempDir: "../testdata/image2", SysctlSettingsFile: "../testdata/image2/rootfs/etc/sysctl.d/00-sysctl.conf"},
FlagInfo: &input.FlagInfo{BinaryTypesSelected: []string{"Sysctl-settings"}},
want: &Differences{SysctlSettings: testSysctlSettingsDiff}},
} {
got, _ := Diff(tc.Image1, tc.Image2, tc.FlagInfo)
if !utilities.EqualArrays(tc.want.Version, got.Version) {
t.Fatalf("Diff expected version %v, got: %v", tc.want.Version, got.Version)
}
if !utilities.EqualArrays(tc.want.BuildID, got.BuildID) {
t.Fatalf("Diff expected BuildID %v, got: %v", tc.want.BuildID, got.BuildID)
}
if tc.want.Rootfs != got.Rootfs {
t.Fatalf("Diff expected Rootfs diff \n%v\ngot:\n%v", tc.want.Rootfs, got.Rootfs)
}
for etcEntry := range tc.want.OSConfigs {
if res, _ := utilities.CmpMapValues(tc.want.OSConfigs, got.OSConfigs, etcEntry); res != 0 {
t.Fatalf("Diff expected OSConfigs \n%v\ngot:\n%v", tc.want.OSConfigs, got.OSConfigs)
}
}
if tc.want.Stateful != got.Stateful {
t.Fatalf("Diff expected stateful diff \n%v\ngot:\n%v", tc.want.Stateful, got.Stateful)
}
if tc.want.PartitionStructure != got.PartitionStructure {
t.Fatalf("Diff expected partition structure diff \n$%v$\ngot:\n$%v$", tc.want.PartitionStructure, got.PartitionStructure)
}
for kclParameter, diff := range tc.want.KernelCommandLine {
if diff != got.KernelCommandLine[kclParameter] {
t.Fatalf("Diff expected kernel command line \n$%v$\ngot:\n$%v$", tc.want.KernelCommandLine, got.KernelCommandLine)
}
}
if tc.want.KernelConfigs != got.KernelConfigs {
t.Fatalf("Diff expected kernel configs diff \n$%v$\ngot:\n$%v$", tc.want.KernelConfigs, got.KernelConfigs)
}
if tc.want.SysctlSettings != got.SysctlSettings {
t.Fatalf("Diff expected sysctl settings \n$%v$\ngot:\n$%v$", tc.want.SysctlSettings, got.SysctlSettings)
}
}
}