func testInsertLayerDelete(t *testing.T, datastore database.Datastore) { err := datastore.DeleteLayer("TestInsertLayerX") assert.Equal(t, cerrors.ErrNotFound, err) err = datastore.DeleteLayer("TestInsertLayer3") assert.Nil(t, err) _, err = datastore.FindLayer("TestInsertLayer3", false, false) assert.Equal(t, cerrors.ErrNotFound, err) _, err = datastore.FindLayer("TestInsertLayer4a", false, false) assert.Equal(t, cerrors.ErrNotFound, err) _, err = datastore.FindLayer("TestInsertLayer4b", true, false) assert.Equal(t, cerrors.ErrNotFound, err) }
// Process detects the Namespace of a layer, the features it adds/removes, and // then stores everything in the database. // TODO(Quentin-M): We could have a goroutine that looks for layers that have been analyzed with an // older engine version and that processes them. func Process(datastore database.Datastore, imageFormat, name, parentName, path string, headers map[string]string) error { // Verify parameters. if name == "" { return cerrors.NewBadRequestError("could not process a layer which does not have a name") } if path == "" { return cerrors.NewBadRequestError("could not process a layer which does not have a path") } if imageFormat == "" { return cerrors.NewBadRequestError("could not process a layer which does not have a format") } log.Debugf("layer %s: processing (Location: %s, Engine version: %d, Parent: %s, Format: %s)", name, utils.CleanURL(path), Version, parentName, imageFormat) // Check to see if the layer is already in the database. layer, err := datastore.FindLayer(name, false, false) if err != nil && err != cerrors.ErrNotFound { return err } if err == cerrors.ErrNotFound { // New layer case. layer = database.Layer{Name: name, EngineVersion: Version} // Retrieve the parent if it has one. // We need to get it with its Features in order to diff them. if parentName != "" { parent, err := datastore.FindLayer(parentName, true, false) if err != nil && err != cerrors.ErrNotFound { return err } if err == cerrors.ErrNotFound { log.Warningf("layer %s: the parent layer (%s) is unknown. it must be processed first", name, parentName) return ErrParentUnknown } layer.Parent = &parent } } else { // The layer is already in the database, check if we need to update it. if layer.EngineVersion >= Version { log.Debugf(`layer %s: layer content has already been processed in the past with engine %d. Current engine is %d. skipping analysis`, name, layer.EngineVersion, Version) return nil } log.Debugf(`layer %s: layer content has been analyzed in the past with engine %d. Current engine is %d. analyzing again`, name, layer.EngineVersion, Version) } // Analyze the content. layer.Namespace, layer.Features, err = detectContent(imageFormat, name, path, headers, layer.Parent) if err != nil { return err } return datastore.InsertLayer(layer) }
func testInsertLayerUpdate(t *testing.T, datastore database.Datastore) { f7 := database.FeatureVersion{ Feature: database.Feature{ Namespace: database.Namespace{Name: "TestInsertLayerNamespace3"}, Name: "TestInsertLayerFeature7", }, Version: types.NewVersionUnsafe("0.01"), } l3, _ := datastore.FindLayer("TestInsertLayer3", true, false) l3u := database.Layer{ Name: l3.Name, Parent: l3.Parent, Namespace: &database.Namespace{Name: "TestInsertLayerNamespaceUpdated1"}, Features: []database.FeatureVersion{f7}, } l4u := database.Layer{ Name: "TestInsertLayer4", Parent: &database.Layer{Name: "TestInsertLayer3"}, Features: []database.FeatureVersion{f7}, EngineVersion: 2, } // Try to re-insert without increasing the EngineVersion. err := datastore.InsertLayer(l3u) assert.Nil(t, err) l3uf, err := datastore.FindLayer(l3u.Name, true, false) if assert.Nil(t, err) { assert.Equal(t, l3.Namespace.Name, l3uf.Namespace.Name) assert.Equal(t, l3.EngineVersion, l3uf.EngineVersion) assert.Len(t, l3uf.Features, len(l3.Features)) } // Update layer l3. // Verify that the Namespace, EngineVersion and FeatureVersions got updated. l3u.EngineVersion = 2 err = datastore.InsertLayer(l3u) assert.Nil(t, err) l3uf, err = datastore.FindLayer(l3u.Name, true, false) if assert.Nil(t, err) { assert.Equal(t, l3u.Namespace.Name, l3uf.Namespace.Name) assert.Equal(t, l3u.EngineVersion, l3uf.EngineVersion) if assert.Len(t, l3uf.Features, 1) { assert.True(t, cmpFV(l3uf.Features[0], f7), "Updated layer should have %#v but actually have %#v", f7, l3uf.Features[0]) } } // Update layer l4. // Verify that the Namespace got updated from its new Parent's, and also verify the // EnginVersion and FeatureVersions. l4u.Parent = &l3uf err = datastore.InsertLayer(l4u) assert.Nil(t, err) l4uf, err := datastore.FindLayer(l3u.Name, true, false) if assert.Nil(t, err) { assert.Equal(t, l3u.Namespace.Name, l4uf.Namespace.Name) assert.Equal(t, l4u.EngineVersion, l4uf.EngineVersion) if assert.Len(t, l4uf.Features, 1) { assert.True(t, cmpFV(l3uf.Features[0], f7), "Updated layer should have %#v but actually have %#v", f7, l4uf.Features[0]) } } }
func testInsertLayerTree(t *testing.T, datastore database.Datastore) { f1 := database.FeatureVersion{ Feature: database.Feature{ Namespace: database.Namespace{Name: "TestInsertLayerNamespace2"}, Name: "TestInsertLayerFeature1", }, Version: types.NewVersionUnsafe("1.0"), } f2 := database.FeatureVersion{ Feature: database.Feature{ Namespace: database.Namespace{Name: "TestInsertLayerNamespace2"}, Name: "TestInsertLayerFeature2", }, Version: types.NewVersionUnsafe("0.34"), } f3 := database.FeatureVersion{ Feature: database.Feature{ Namespace: database.Namespace{Name: "TestInsertLayerNamespace2"}, Name: "TestInsertLayerFeature3", }, Version: types.NewVersionUnsafe("0.56"), } f4 := database.FeatureVersion{ Feature: database.Feature{ Namespace: database.Namespace{Name: "TestInsertLayerNamespace3"}, Name: "TestInsertLayerFeature2", }, Version: types.NewVersionUnsafe("0.34"), } f5 := database.FeatureVersion{ Feature: database.Feature{ Namespace: database.Namespace{Name: "TestInsertLayerNamespace3"}, Name: "TestInsertLayerFeature3", }, Version: types.NewVersionUnsafe("0.56"), } f6 := database.FeatureVersion{ Feature: database.Feature{ Namespace: database.Namespace{Name: "TestInsertLayerNamespace3"}, Name: "TestInsertLayerFeature4", }, Version: types.NewVersionUnsafe("0.666"), } layers := []database.Layer{ { Name: "TestInsertLayer1", }, { Name: "TestInsertLayer2", Parent: &database.Layer{Name: "TestInsertLayer1"}, Namespace: &database.Namespace{Name: "TestInsertLayerNamespace1"}, }, // This layer changes the namespace and adds Features. { Name: "TestInsertLayer3", Parent: &database.Layer{Name: "TestInsertLayer2"}, Namespace: &database.Namespace{Name: "TestInsertLayerNamespace2"}, Features: []database.FeatureVersion{f1, f2, f3}, }, // This layer covers the case where the last layer doesn't provide any new Feature. { Name: "TestInsertLayer4a", Parent: &database.Layer{Name: "TestInsertLayer3"}, Features: []database.FeatureVersion{f1, f2, f3}, }, // This layer covers the case where the last layer provides Features. // It also modifies the Namespace ("upgrade") but keeps some Features not upgraded, their // Namespaces should then remain unchanged. { Name: "TestInsertLayer4b", Parent: &database.Layer{Name: "TestInsertLayer3"}, Namespace: &database.Namespace{Name: "TestInsertLayerNamespace3"}, Features: []database.FeatureVersion{ // Deletes TestInsertLayerFeature1. // Keep TestInsertLayerFeature2 (old Namespace should be kept): f4, // Upgrades TestInsertLayerFeature3 (with new Namespace): f5, // Adds TestInsertLayerFeature4: f6, }, }, } var err error retrievedLayers := make(map[string]database.Layer) for _, layer := range layers { if layer.Parent != nil { // Retrieve from database its parent and assign. parent := retrievedLayers[layer.Parent.Name] layer.Parent = &parent } err = datastore.InsertLayer(layer) assert.Nil(t, err) retrievedLayers[layer.Name], err = datastore.FindLayer(layer.Name, true, false) assert.Nil(t, err) } l4a := retrievedLayers["TestInsertLayer4a"] if assert.NotNil(t, l4a.Namespace) { assert.Equal(t, "TestInsertLayerNamespace2", l4a.Namespace.Name) } assert.Len(t, l4a.Features, 3) for _, featureVersion := range l4a.Features { if cmpFV(featureVersion, f1) && cmpFV(featureVersion, f2) && cmpFV(featureVersion, f3) { assert.Error(t, fmt.Errorf("TestInsertLayer4a contains an unexpected package: %#v. Should contain %#v and %#v and %#v.", featureVersion, f1, f2, f3)) } } l4b := retrievedLayers["TestInsertLayer4b"] if assert.NotNil(t, l4b.Namespace) { assert.Equal(t, "TestInsertLayerNamespace3", l4b.Namespace.Name) } assert.Len(t, l4b.Features, 3) for _, featureVersion := range l4b.Features { if cmpFV(featureVersion, f2) && cmpFV(featureVersion, f5) && cmpFV(featureVersion, f6) { assert.Error(t, fmt.Errorf("TestInsertLayer4a contains an unexpected package: %#v. Should contain %#v and %#v and %#v.", featureVersion, f2, f4, f6)) } } }