268 lines
8.7 KiB
Go
268 lines
8.7 KiB
Go
|
// Copyright 2019 clair authors
|
||
|
//
|
||
|
// 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 clair
|
||
|
|
||
|
import (
|
||
|
"testing"
|
||
|
|
||
|
"github.com/stretchr/testify/require"
|
||
|
|
||
|
"github.com/coreos/clair/database"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
dpkg = database.NewFeatureDetector("dpkg", "1.0")
|
||
|
rpm = database.NewFeatureDetector("rpm", "1.0")
|
||
|
pip = database.NewFeatureDetector("pip", "1.0")
|
||
|
python = database.NewNamespaceDetector("python", "1.0")
|
||
|
osrelease = database.NewNamespaceDetector("os-release", "1.0")
|
||
|
ubuntu = *database.NewNamespace("ubuntu:14.04", "dpkg")
|
||
|
ubuntu16 = *database.NewNamespace("ubuntu:16.04", "dpkg")
|
||
|
python2 = *database.NewNamespace("python:2", "pip")
|
||
|
sed = *database.NewSourcePackage("sed", "4.4-2", "dpkg")
|
||
|
sedBin = *database.NewBinaryPackage("sed", "4.4-2", "dpkg")
|
||
|
tar = *database.NewBinaryPackage("tar", "1.29b-2", "dpkg")
|
||
|
scipy = *database.NewSourcePackage("scipy", "3.0.0", "pip")
|
||
|
|
||
|
detectors = []database.Detector{dpkg, osrelease, rpm}
|
||
|
multinamespaceDetectors = []database.Detector{dpkg, osrelease, pip}
|
||
|
)
|
||
|
|
||
|
// layerBuilder is for helping constructing the layer test artifacts.
|
||
|
type layerBuilder struct {
|
||
|
layer *database.Layer
|
||
|
}
|
||
|
|
||
|
func newLayerBuilder(hash string) *layerBuilder {
|
||
|
return &layerBuilder{&database.Layer{Hash: hash, By: detectors}}
|
||
|
}
|
||
|
|
||
|
func (b *layerBuilder) addNamespace(detector database.Detector, ns database.Namespace) *layerBuilder {
|
||
|
b.layer.Namespaces = append(b.layer.Namespaces, database.LayerNamespace{
|
||
|
Namespace: ns,
|
||
|
By: detector,
|
||
|
})
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
func (b *layerBuilder) addFeature(detector database.Detector, f database.Feature) *layerBuilder {
|
||
|
b.layer.Features = append(b.layer.Features, database.LayerFeature{
|
||
|
Feature: f,
|
||
|
By: detector,
|
||
|
})
|
||
|
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
var testImage = []*database.Layer{
|
||
|
// empty layer
|
||
|
newLayerBuilder("0").layer,
|
||
|
// ubuntu namespace
|
||
|
newLayerBuilder("1").addNamespace(osrelease, ubuntu).layer,
|
||
|
// install sed
|
||
|
newLayerBuilder("2").addFeature(dpkg, sed).layer,
|
||
|
// install tar
|
||
|
newLayerBuilder("3").addFeature(dpkg, sed).addFeature(dpkg, tar).layer,
|
||
|
// remove tar
|
||
|
newLayerBuilder("4").addFeature(dpkg, sed).layer,
|
||
|
// upgrade ubuntu
|
||
|
newLayerBuilder("5").addNamespace(osrelease, ubuntu16).layer,
|
||
|
// no change to the detectable files
|
||
|
newLayerBuilder("6").layer,
|
||
|
// change to the package installer database but no features are affected.
|
||
|
newLayerBuilder("7").addFeature(dpkg, sed).layer,
|
||
|
}
|
||
|
|
||
|
var clairLimit = []*database.Layer{
|
||
|
// TODO(sidac): how about install rpm package under ubuntu?
|
||
|
newLayerBuilder("1").addNamespace(osrelease, ubuntu).layer,
|
||
|
newLayerBuilder("2").addFeature(rpm, sed).layer,
|
||
|
}
|
||
|
|
||
|
var multipleNamespace = []*database.Layer{
|
||
|
// TODO(sidac): support for multiple namespaces
|
||
|
}
|
||
|
|
||
|
var invalidNamespace = []*database.Layer{
|
||
|
// add package without namespace, this indicates that the namespace detector
|
||
|
// could not detect the namespace.
|
||
|
newLayerBuilder("0").addFeature(dpkg, sed).layer,
|
||
|
}
|
||
|
|
||
|
var multiplePackagesOnFirstLayer = []*database.Layer{
|
||
|
newLayerBuilder("0").addFeature(dpkg, sed).addFeature(dpkg, tar).addFeature(dpkg, sedBin).addNamespace(osrelease, ubuntu16).layer,
|
||
|
}
|
||
|
|
||
|
func TestAddLayer(t *testing.T) {
|
||
|
cases := []struct {
|
||
|
title string
|
||
|
image []*database.Layer
|
||
|
|
||
|
expectedAncestry database.Ancestry
|
||
|
}{
|
||
|
{
|
||
|
title: "empty image",
|
||
|
expectedAncestry: database.Ancestry{Name: ancestryName([]string{}), By: detectors},
|
||
|
},
|
||
|
{
|
||
|
title: "empty layer",
|
||
|
image: testImage[:1],
|
||
|
expectedAncestry: database.Ancestry{Name: ancestryName([]string{"0"}), By: detectors, Layers: []database.AncestryLayer{{Hash: "0"}}},
|
||
|
},
|
||
|
{
|
||
|
title: "ubuntu",
|
||
|
image: testImage[:2],
|
||
|
expectedAncestry: database.Ancestry{
|
||
|
Name: ancestryName([]string{"0", "1"}),
|
||
|
By: detectors,
|
||
|
Layers: []database.AncestryLayer{{Hash: "0"}, {Hash: "1"}},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
title: "ubuntu install sed",
|
||
|
image: testImage[:3],
|
||
|
expectedAncestry: database.Ancestry{
|
||
|
Name: ancestryName([]string{"0", "1", "2"}),
|
||
|
By: detectors,
|
||
|
Layers: []database.AncestryLayer{{Hash: "0"}, {Hash: "1"}, {Hash: "2", Features: []database.AncestryFeature{
|
||
|
{
|
||
|
NamespacedFeature: database.NamespacedFeature{Feature: sed, Namespace: ubuntu},
|
||
|
FeatureBy: dpkg,
|
||
|
NamespaceBy: osrelease,
|
||
|
},
|
||
|
}}},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
title: "ubuntu install tar",
|
||
|
image: testImage[:4],
|
||
|
expectedAncestry: database.Ancestry{
|
||
|
Name: ancestryName([]string{"0", "1", "2", "3"}),
|
||
|
By: detectors,
|
||
|
Layers: []database.AncestryLayer{{Hash: "0"}, {Hash: "1"}, {Hash: "2", Features: []database.AncestryFeature{
|
||
|
{
|
||
|
NamespacedFeature: database.NamespacedFeature{Feature: sed, Namespace: ubuntu},
|
||
|
FeatureBy: dpkg,
|
||
|
NamespaceBy: osrelease,
|
||
|
},
|
||
|
}}, {
|
||
|
Hash: "3", Features: []database.AncestryFeature{
|
||
|
{
|
||
|
NamespacedFeature: database.NamespacedFeature{Feature: tar, Namespace: ubuntu},
|
||
|
FeatureBy: dpkg,
|
||
|
NamespaceBy: osrelease,
|
||
|
},
|
||
|
},
|
||
|
}},
|
||
|
},
|
||
|
}, {
|
||
|
title: "ubuntu uninstall tar",
|
||
|
image: testImage[:5],
|
||
|
expectedAncestry: database.Ancestry{
|
||
|
Name: ancestryName([]string{"0", "1", "2", "3", "4"}),
|
||
|
By: detectors,
|
||
|
Layers: []database.AncestryLayer{{Hash: "0"}, {Hash: "1"}, {Hash: "2", Features: []database.AncestryFeature{
|
||
|
{
|
||
|
NamespacedFeature: database.NamespacedFeature{Feature: sed, Namespace: ubuntu},
|
||
|
FeatureBy: dpkg,
|
||
|
NamespaceBy: osrelease,
|
||
|
},
|
||
|
}}, {Hash: "3"}, {Hash: "4"}},
|
||
|
},
|
||
|
}, {
|
||
|
title: "ubuntu upgrade",
|
||
|
image: testImage[:6],
|
||
|
expectedAncestry: database.Ancestry{
|
||
|
Name: ancestryName([]string{"0", "1", "2", "3", "4", "5"}),
|
||
|
By: detectors,
|
||
|
Layers: []database.AncestryLayer{{Hash: "0"}, {Hash: "1"}, {Hash: "2"}, {Hash: "3"}, {Hash: "4"}, {Hash: "5", Features: []database.AncestryFeature{
|
||
|
{
|
||
|
NamespacedFeature: database.NamespacedFeature{Feature: sed, Namespace: ubuntu16},
|
||
|
FeatureBy: dpkg,
|
||
|
NamespaceBy: osrelease,
|
||
|
}}},
|
||
|
},
|
||
|
},
|
||
|
}, {
|
||
|
title: "no change to the detectable files",
|
||
|
image: testImage[:7],
|
||
|
expectedAncestry: database.Ancestry{
|
||
|
Name: ancestryName([]string{"0", "1", "2", "3", "4", "5", "6"}),
|
||
|
By: detectors,
|
||
|
Layers: []database.AncestryLayer{{Hash: "0"}, {Hash: "1"}, {Hash: "2"}, {Hash: "3"}, {Hash: "4"}, {Hash: "5", Features: []database.AncestryFeature{
|
||
|
{
|
||
|
NamespacedFeature: database.NamespacedFeature{Feature: sed, Namespace: ubuntu16},
|
||
|
FeatureBy: dpkg,
|
||
|
NamespaceBy: osrelease,
|
||
|
}}}, {Hash: "6"}},
|
||
|
},
|
||
|
}, {
|
||
|
title: "change to the package installer database but no features are affected.",
|
||
|
image: testImage[:8],
|
||
|
expectedAncestry: database.Ancestry{
|
||
|
Name: ancestryName([]string{"0", "1", "2", "3", "4", "5", "6", "7"}),
|
||
|
By: detectors,
|
||
|
Layers: []database.AncestryLayer{{Hash: "0"}, {Hash: "1"}, {Hash: "2"}, {Hash: "3"}, {Hash: "4"}, {Hash: "5", Features: []database.AncestryFeature{
|
||
|
{
|
||
|
NamespacedFeature: database.NamespacedFeature{Feature: sed, Namespace: ubuntu16},
|
||
|
FeatureBy: dpkg,
|
||
|
NamespaceBy: osrelease,
|
||
|
}}}, {Hash: "6"}, {Hash: "7"}},
|
||
|
},
|
||
|
}, {
|
||
|
title: "layers with features and namespace.",
|
||
|
image: multiplePackagesOnFirstLayer,
|
||
|
expectedAncestry: database.Ancestry{
|
||
|
Name: ancestryName([]string{"0"}),
|
||
|
By: detectors,
|
||
|
Layers: []database.AncestryLayer{
|
||
|
{
|
||
|
Hash: "0",
|
||
|
Features: []database.AncestryFeature{
|
||
|
{
|
||
|
NamespacedFeature: database.NamespacedFeature{Feature: sed, Namespace: ubuntu16},
|
||
|
FeatureBy: dpkg,
|
||
|
NamespaceBy: osrelease,
|
||
|
},
|
||
|
{
|
||
|
NamespacedFeature: database.NamespacedFeature{Feature: sedBin, Namespace: ubuntu16},
|
||
|
FeatureBy: dpkg,
|
||
|
NamespaceBy: osrelease,
|
||
|
},
|
||
|
{
|
||
|
NamespacedFeature: database.NamespacedFeature{Feature: tar, Namespace: ubuntu16},
|
||
|
FeatureBy: dpkg,
|
||
|
NamespaceBy: osrelease,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, test := range cases {
|
||
|
t.Run(test.title, func(t *testing.T) {
|
||
|
builder := NewAncestryBuilder(detectors)
|
||
|
for _, layer := range test.image {
|
||
|
builder.AddLeafLayer(layer)
|
||
|
}
|
||
|
|
||
|
ancestry := builder.Ancestry("")
|
||
|
require.True(t, database.AssertAncestryEqual(t, &test.expectedAncestry, ancestry))
|
||
|
})
|
||
|
}
|
||
|
}
|