mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-02-09 09:16:41 +08:00
Implemented GetFeaturesThatNeedUpdate() method
Returns all features that could be updated --HG-- branch : dev
This commit is contained in:
@@ -2,7 +2,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Autofac;
|
using Autofac;
|
||||||
using Moq;
|
|
||||||
using NHibernate;
|
using NHibernate;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Orchard.ContentManagement.Records;
|
using Orchard.ContentManagement.Records;
|
||||||
@@ -10,7 +9,6 @@ using Orchard.Data;
|
|||||||
using Orchard.Environment.Configuration;
|
using Orchard.Environment.Configuration;
|
||||||
using Orchard.Environment.Extensions;
|
using Orchard.Environment.Extensions;
|
||||||
using Orchard.Environment.Extensions.Folders;
|
using Orchard.Environment.Extensions.Folders;
|
||||||
using Orchard.Environment.Extensions.Loaders;
|
|
||||||
using Orchard.Environment.Extensions.Models;
|
using Orchard.Environment.Extensions.Models;
|
||||||
using Orchard.Tests.ContentManagement;
|
using Orchard.Tests.ContentManagement;
|
||||||
using Orchard.DataMigration;
|
using Orchard.DataMigration;
|
||||||
@@ -19,7 +17,6 @@ namespace Orchard.Tests.DataMigration {
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class DataMigrationTests {
|
public class DataMigrationTests {
|
||||||
private IContainer _container;
|
private IContainer _container;
|
||||||
private IExtensionManager _manager;
|
|
||||||
private StubFolders _folders;
|
private StubFolders _folders;
|
||||||
private IDataMigrationManager _dataMigrationManager;
|
private IDataMigrationManager _dataMigrationManager;
|
||||||
private IRepository<DataMigrationRecord> _repository;
|
private IRepository<DataMigrationRecord> _repository;
|
||||||
@@ -27,13 +24,8 @@ namespace Orchard.Tests.DataMigration {
|
|||||||
private ISessionFactory _sessionFactory;
|
private ISessionFactory _sessionFactory;
|
||||||
private ISession _session;
|
private ISession _session;
|
||||||
|
|
||||||
[SetUp]
|
[TestFixtureSetUp]
|
||||||
public void Init() {
|
public void CreateDb() {
|
||||||
Init(Enumerable.Empty<Type>());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Init(IEnumerable<Type> dataMigrations) {
|
|
||||||
|
|
||||||
var databaseFileName = System.IO.Path.GetTempFileName();
|
var databaseFileName = System.IO.Path.GetTempFileName();
|
||||||
_sessionFactory = DataUtility.CreateSessionFactory(
|
_sessionFactory = DataUtility.CreateSessionFactory(
|
||||||
databaseFileName,
|
databaseFileName,
|
||||||
@@ -41,7 +33,17 @@ namespace Orchard.Tests.DataMigration {
|
|||||||
typeof(ContentItemVersionRecord),
|
typeof(ContentItemVersionRecord),
|
||||||
typeof(ContentItemRecord),
|
typeof(ContentItemRecord),
|
||||||
typeof(ContentTypeRecord));
|
typeof(ContentTypeRecord));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitDb() {
|
||||||
|
foreach ( var record in _repository.Fetch(m => true) ) {
|
||||||
|
_repository.Delete(record);
|
||||||
|
}
|
||||||
|
_repository.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init(IEnumerable<Type> dataMigrations) {
|
||||||
|
|
||||||
var builder = new ContainerBuilder();
|
var builder = new ContainerBuilder();
|
||||||
_folders = new StubFolders();
|
_folders = new StubFolders();
|
||||||
|
|
||||||
@@ -58,10 +60,11 @@ namespace Orchard.Tests.DataMigration {
|
|||||||
builder.RegisterType(type).As<IDataMigration>();
|
builder.RegisterType(type).As<IDataMigration>();
|
||||||
}
|
}
|
||||||
_container = builder.Build();
|
_container = builder.Build();
|
||||||
_manager = _container.Resolve<IExtensionManager>();
|
_container.Resolve<IExtensionManager>();
|
||||||
_dataMigrationManager = _container.Resolve<IDataMigrationManager>();
|
_dataMigrationManager = _container.Resolve<IDataMigrationManager>();
|
||||||
_repository = _container.Resolve<IRepository<DataMigrationRecord>>();
|
_repository = _container.Resolve<IRepository<DataMigrationRecord>>();
|
||||||
|
|
||||||
|
InitDb();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StubFolders : IExtensionFolders {
|
public class StubFolders : IExtensionFolders {
|
||||||
@@ -144,6 +147,7 @@ namespace Orchard.Tests.DataMigration {
|
|||||||
return 999;
|
return 999;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DataMigrationDependenciesModule2 : IDataMigration {
|
public class DataMigrationDependenciesModule2 : IDataMigration {
|
||||||
public string Feature {
|
public string Feature {
|
||||||
get { return "Feature2"; }
|
get { return "Feature2"; }
|
||||||
@@ -165,9 +169,41 @@ namespace Orchard.Tests.DataMigration {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class DataMigrationFeatureNeedUpdate1 : IDataMigration {
|
||||||
|
public string Feature {
|
||||||
|
get { return "Feature1"; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class DataMigrationFeatureNeedUpdate2 : IDataMigration {
|
||||||
|
public string Feature {
|
||||||
|
get { return "Feature2"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Create() {
|
||||||
|
return 999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DataMigrationFeatureNeedUpdate3 : IDataMigration {
|
||||||
|
public string Feature {
|
||||||
|
get { return "Feature3"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Create() {
|
||||||
|
return 999;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int UpdateFrom42() {
|
||||||
|
return 999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void DataMigrationShouldDoNothingIfNoDataMigrationIsProvidedForFeature() {
|
public void DataMigrationShouldDoNothingIfNoDataMigrationIsProvidedForFeature() {
|
||||||
Init(new Type[] {typeof (DataMigrationEmpty)});
|
Init(new[] {typeof (DataMigrationEmpty)});
|
||||||
|
|
||||||
_folders.Manifests.Add("Module2", @"
|
_folders.Manifests.Add("Module2", @"
|
||||||
name: Module2
|
name: Module2
|
||||||
@@ -184,7 +220,7 @@ features:
|
|||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void DataMigrationShouldDoNothingIfNoUpgradeOrCreateMethodWasFound() {
|
public void DataMigrationShouldDoNothingIfNoUpgradeOrCreateMethodWasFound() {
|
||||||
Init(new Type[] { typeof(DataMigration11) });
|
Init(new[] { typeof(DataMigration11) });
|
||||||
|
|
||||||
_folders.Manifests.Add("Module1", @"
|
_folders.Manifests.Add("Module1", @"
|
||||||
name: Module1
|
name: Module1
|
||||||
@@ -201,7 +237,7 @@ features:
|
|||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void CreateShouldReturnVersionNumber() {
|
public void CreateShouldReturnVersionNumber() {
|
||||||
Init(new Type[] { typeof(DataMigration11Create) });
|
Init(new[] { typeof(DataMigration11Create) });
|
||||||
|
|
||||||
_folders.Manifests.Add("Module1", @"
|
_folders.Manifests.Add("Module1", @"
|
||||||
name: Module1
|
name: Module1
|
||||||
@@ -220,7 +256,7 @@ features:
|
|||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void CreateCanBeFollowedByUpdates() {
|
public void CreateCanBeFollowedByUpdates() {
|
||||||
Init(new Type[] {typeof (DataMigrationCreateCanBeFollowedByUpdates)});
|
Init(new[] {typeof (DataMigrationCreateCanBeFollowedByUpdates)});
|
||||||
|
|
||||||
_folders.Manifests.Add("Module1", @"
|
_folders.Manifests.Add("Module1", @"
|
||||||
name: Module1
|
name: Module1
|
||||||
@@ -238,7 +274,7 @@ features:
|
|||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void SameMigrationClassCanEvolve() {
|
public void SameMigrationClassCanEvolve() {
|
||||||
Init(new Type[] { typeof(DataMigrationSameMigrationClassCanEvolve) });
|
Init(new[] { typeof(DataMigrationSameMigrationClassCanEvolve) });
|
||||||
|
|
||||||
_folders.Manifests.Add("Module1", @"
|
_folders.Manifests.Add("Module1", @"
|
||||||
name: Module1
|
name: Module1
|
||||||
@@ -248,7 +284,7 @@ features:
|
|||||||
Feature1:
|
Feature1:
|
||||||
Description: Feature
|
Description: Feature
|
||||||
");
|
");
|
||||||
_repository.Create(new DataMigrationRecord() {
|
_repository.Create(new DataMigrationRecord {
|
||||||
Current = 42,
|
Current = 42,
|
||||||
DataMigrationClass = "Orchard.Tests.DataMigration.DataMigrationTests+DataMigrationSameMigrationClassCanEvolve"
|
DataMigrationClass = "Orchard.Tests.DataMigration.DataMigrationTests+DataMigrationSameMigrationClassCanEvolve"
|
||||||
});
|
});
|
||||||
@@ -261,7 +297,7 @@ features:
|
|||||||
[Test]
|
[Test]
|
||||||
public void DependenciesShouldBeUpgradedFirst() {
|
public void DependenciesShouldBeUpgradedFirst() {
|
||||||
|
|
||||||
Init(new Type[] { typeof(DataMigrationDependenciesModule1), typeof(DataMigrationDependenciesModule2) });
|
Init(new[] { typeof(DataMigrationDependenciesModule1), typeof(DataMigrationDependenciesModule2) });
|
||||||
|
|
||||||
_folders.Manifests.Add("Module1", @"
|
_folders.Manifests.Add("Module1", @"
|
||||||
name: Module1
|
name: Module1
|
||||||
@@ -290,7 +326,7 @@ features:
|
|||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void DataMigrationImplShouldGetASchemaBuilder() {
|
public void DataMigrationImplShouldGetASchemaBuilder() {
|
||||||
Init(new Type[] { typeof(DataMigrationWithSchemaBuilder) });
|
Init(new[] { typeof(DataMigrationWithSchemaBuilder) });
|
||||||
|
|
||||||
_folders.Manifests.Add("Module1", @"
|
_folders.Manifests.Add("Module1", @"
|
||||||
name: Module1
|
name: Module1
|
||||||
@@ -304,5 +340,54 @@ features:
|
|||||||
_dataMigrationManager.Update("Feature1");
|
_dataMigrationManager.Update("Feature1");
|
||||||
Assert.That(_repository.Table.Count(), Is.EqualTo(1));
|
Assert.That(_repository.Table.Count(), Is.EqualTo(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ShouldDetectFeaturesThatNeedUpdates() {
|
||||||
|
|
||||||
|
Init(new[] { typeof(DataMigrationFeatureNeedUpdate1), typeof(DataMigrationFeatureNeedUpdate2), typeof(DataMigrationFeatureNeedUpdate3) });
|
||||||
|
|
||||||
|
_folders.Manifests.Add("Module1", @"
|
||||||
|
name: Module1
|
||||||
|
version: 0.1
|
||||||
|
orchardversion: 1
|
||||||
|
features:
|
||||||
|
Feature1:
|
||||||
|
Description: Feature
|
||||||
|
Feature2:
|
||||||
|
Description: Feature
|
||||||
|
Feature3:
|
||||||
|
Description: Feature
|
||||||
|
Feature4:
|
||||||
|
Description: Feature
|
||||||
|
");
|
||||||
|
|
||||||
|
// even if there is a data migration class, as it is empty there should me no migration to do
|
||||||
|
Assert.That(_dataMigrationManager.GetFeaturesThatNeedUpdate().Contains("Feature1"), Is.False);
|
||||||
|
|
||||||
|
// there is no available class for this feature
|
||||||
|
Assert.That(_dataMigrationManager.GetFeaturesThatNeedUpdate().Contains("Feature4"), Is.False);
|
||||||
|
|
||||||
|
// there is a create method and no record in db, so let's create it
|
||||||
|
Assert.That(_dataMigrationManager.GetFeaturesThatNeedUpdate().Contains("Feature2"), Is.True);
|
||||||
|
|
||||||
|
// there is an UpdateFrom42 method, so it should be fired if Current == 42
|
||||||
|
|
||||||
|
_repository.Create(new DataMigrationRecord {
|
||||||
|
Current = 42,
|
||||||
|
DataMigrationClass = "Orchard.Tests.DataMigration.DataMigrationTests+DataMigrationFeatureNeedUpdate3"
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.That(_dataMigrationManager.GetFeaturesThatNeedUpdate().Contains("Feature3"), Is.True);
|
||||||
|
|
||||||
|
_repository.Delete(_repository.Fetch(m => m.Current == 42).First());
|
||||||
|
_repository.Flush();
|
||||||
|
|
||||||
|
_repository.Create(new DataMigrationRecord {
|
||||||
|
Current = 43,
|
||||||
|
DataMigrationClass = "Orchard.Tests.DataMigration.DataMigrationTests+DataMigrationFeatureNeedUpdate3"
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.That(_dataMigrationManager.GetFeaturesThatNeedUpdate().Contains("Feature3"), Is.False);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,7 +38,38 @@ namespace Orchard.DataMigration {
|
|||||||
public ILogger Logger { get; set; }
|
public ILogger Logger { get; set; }
|
||||||
|
|
||||||
public IEnumerable<string> GetFeaturesThatNeedUpdate() {
|
public IEnumerable<string> GetFeaturesThatNeedUpdate() {
|
||||||
throw new NotImplementedException();
|
|
||||||
|
var features = new List<string>();
|
||||||
|
|
||||||
|
// compare current version and available migration methods for each migration class
|
||||||
|
foreach ( var dataMigration in _dataMigrations ) {
|
||||||
|
|
||||||
|
// get current version for this migration
|
||||||
|
var dataMigrationRecord = GetDataMigrationRecord(dataMigration);
|
||||||
|
|
||||||
|
var current = 0;
|
||||||
|
if (dataMigrationRecord != null) {
|
||||||
|
current = dataMigrationRecord.Current;
|
||||||
|
}
|
||||||
|
|
||||||
|
// do we need to call Create() ?
|
||||||
|
if (current == 0) {
|
||||||
|
|
||||||
|
// try to resolve a Create method
|
||||||
|
if ( GetCreateMethod(dataMigration) != null ) {
|
||||||
|
features.Add(dataMigration.Feature);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var lookupTable = CreateUpgradeLookupTable(dataMigration);
|
||||||
|
|
||||||
|
if(lookupTable.ContainsKey(current)) {
|
||||||
|
features.Add(dataMigration.Feature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return features;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(IEnumerable<string> features) {
|
public void Update(IEnumerable<string> features) {
|
||||||
@@ -71,7 +102,6 @@ namespace Orchard.DataMigration {
|
|||||||
// get current version for this migration
|
// get current version for this migration
|
||||||
var dataMigrationRecord = GetDataMigrationRecord(tempMigration);
|
var dataMigrationRecord = GetDataMigrationRecord(tempMigration);
|
||||||
|
|
||||||
var updateMethodNameRegex = new Regex(@"^UpdateFrom(?<version>\d+)$", RegexOptions.Compiled);
|
|
||||||
var current = 0;
|
var current = 0;
|
||||||
if(dataMigrationRecord != null) {
|
if(dataMigrationRecord != null) {
|
||||||
current = dataMigrationRecord.Current;
|
current = dataMigrationRecord.Current;
|
||||||
@@ -81,8 +111,8 @@ namespace Orchard.DataMigration {
|
|||||||
if(current == 0) {
|
if(current == 0) {
|
||||||
// try to resolve a Create method
|
// try to resolve a Create method
|
||||||
|
|
||||||
var createMethod = migration.GetType().GetMethod("Create", BindingFlags.Public | BindingFlags.Instance);
|
var createMethod = GetCreateMethod(migration);
|
||||||
if(createMethod != null && createMethod.ReturnType == typeof(int)) {
|
if(createMethod != null) {
|
||||||
current = (int)createMethod.Invoke(migration, new object[0]);
|
current = (int)createMethod.Invoke(migration, new object[0]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -91,16 +121,7 @@ namespace Orchard.DataMigration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update methods might also be called after Create()
|
var lookupTable = CreateUpgradeLookupTable(migration);
|
||||||
var lookupTable = new Dictionary<int, MethodInfo>();
|
|
||||||
|
|
||||||
// construct a lookup table with all managed initial versions
|
|
||||||
foreach(var methodInfo in migration.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance)) {
|
|
||||||
var match = updateMethodNameRegex.Match(methodInfo.Name);
|
|
||||||
if(match.Success) {
|
|
||||||
lookupTable.Add(int.Parse(match.Groups["version"].Value), methodInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while(lookupTable.ContainsKey(current)) {
|
while(lookupTable.ContainsKey(current)) {
|
||||||
try {
|
try {
|
||||||
@@ -154,5 +175,37 @@ namespace Orchard.DataMigration {
|
|||||||
public bool IsFeatureAlreadyInstalled(string feature) {
|
public bool IsFeatureAlreadyInstalled(string feature) {
|
||||||
return GetDataMigrations(feature).Any(dataMigration => GetDataMigrationRecord(dataMigration) != null);
|
return GetDataMigrations(feature).Any(dataMigration => GetDataMigrationRecord(dataMigration) != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a list of all available Update methods from a data migration class, indexed by the version number
|
||||||
|
/// </summary>
|
||||||
|
private static Dictionary<int, MethodInfo> CreateUpgradeLookupTable(IDataMigration dataMigration) {
|
||||||
|
var updateMethodNameRegex = new Regex(@"^UpdateFrom(?<version>\d+)$", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
// update methods might also be called after Create()
|
||||||
|
var lookupTable = new Dictionary<int, MethodInfo>();
|
||||||
|
|
||||||
|
// construct a lookup table with all managed initial versions
|
||||||
|
foreach ( var methodInfo in dataMigration.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance) ) {
|
||||||
|
var match = updateMethodNameRegex.Match(methodInfo.Name);
|
||||||
|
if ( match.Success ) {
|
||||||
|
lookupTable.Add(int.Parse(match.Groups["version"].Value), methodInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lookupTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the Create metho from a data migration class if it's found
|
||||||
|
/// </summary>
|
||||||
|
private static MethodInfo GetCreateMethod(IDataMigration dataMigration) {
|
||||||
|
var methodInfo = dataMigration.GetType().GetMethod("Create", BindingFlags.Public | BindingFlags.Instance);
|
||||||
|
if(methodInfo != null && methodInfo.ReturnType == typeof(int)) {
|
||||||
|
return methodInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user