1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace System.Data.Entity.Migrations
{
using System.Collections.Generic;
using System.Data.Entity.Migrations.Design;
using System.Data.Entity.Migrations.Infrastructure;
using System.Data.Entity.Migrations.Model;
using System.Data.Entity.Migrations.Sql;
using System.Linq;
using Xunit;
using Xunit.Extensions;
public abstract class AutoAndGenerateTestCase<TContextV1, TContextV2> : DbTestCase
where TContextV1 : DbContext
where TContextV2 : DbContext
{
private SqlInterceptor _upVerifier;
private SqlInterceptor _downVerifier;
private ScaffoldedMigration _generatedMigration_v1;
protected bool UpDataLoss { get; set; }
protected bool DownDataLoss { get; set; }
public override void Init(DatabaseProvider provider, ProgrammingLanguage language)
{
base.Init(provider, language);
_upVerifier = new SqlInterceptor(VerifyUpOperations);
_downVerifier = new SqlInterceptor(VerifyDownOperations);
}
[MigrationsTheory]
public void Automatic()
{
ResetDatabaseToV1();
DbMigrationsConfiguration migrationsConfiguration;
try
{
migrationsConfiguration =
CreateMigrationsConfiguration<TContextV2>(scaffoldedMigrations: _generatedMigration_v1);
migrationsConfiguration.SetSqlGenerator(DbProviders.Sql, _upVerifier);
migrationsConfiguration.SetSqlGenerator(DbProviders.SqlCe, _upVerifier);
new DbMigrator(migrationsConfiguration).Update();
Assert.False(UpDataLoss);
}
catch (AutomaticDataLossException)
{
Assert.True(UpDataLoss);
migrationsConfiguration = CreateMigrationsConfiguration<TContextV2>(
automaticDataLossEnabled: true, scaffoldedMigrations: _generatedMigration_v1);
migrationsConfiguration.SetSqlGenerator(DbProviders.Sql, _upVerifier);
migrationsConfiguration.SetSqlGenerator(DbProviders.SqlCe, _upVerifier);
new DbMigrator(migrationsConfiguration).Update();
}
// NOTE: This prevents no-op migrations from silently succeeding
if (!_upVerifier.WasCalled())
{
VerifyUpOperations(Enumerable.Empty<MigrationOperation>());
}
// Bring up via automatic
CreateMigrator<TContextV2>(automaticDataLossEnabled: true, scaffoldedMigrations: _generatedMigration_v1).Update();
try
{
migrationsConfiguration =
CreateMigrationsConfiguration<TContextV2>(scaffoldedMigrations: _generatedMigration_v1);
migrationsConfiguration.SetSqlGenerator(DbProviders.Sql, _downVerifier);
migrationsConfiguration.SetSqlGenerator(DbProviders.SqlCe, _downVerifier);
new DbMigrator(migrationsConfiguration).Update(_generatedMigration_v1.MigrationId);
Assert.False(DownDataLoss);
}
catch (AutomaticDataLossException)
{
Assert.True(DownDataLoss);
migrationsConfiguration = CreateMigrationsConfiguration<TContextV2>(
automaticDataLossEnabled: true, scaffoldedMigrations: _generatedMigration_v1);
migrationsConfiguration.SetSqlGenerator(DbProviders.Sql, _downVerifier);
migrationsConfiguration.SetSqlGenerator(DbProviders.SqlCe, _downVerifier);
new DbMigrator(migrationsConfiguration).Update(_generatedMigration_v1.MigrationId);
}
if (!_downVerifier.WasCalled())
{
VerifyDownOperations(Enumerable.Empty<MigrationOperation>());
}
}
[MigrationsTheory]
[InlineData(ProgrammingLanguage.CSharp)]
[InlineData(ProgrammingLanguage.VB)]
public void Generated(ProgrammingLanguage programmingLanguage)
{
ProgrammingLanguage = programmingLanguage;
ResetDatabaseToV1();
var migrator = CreateMigrator<TContextV2>(scaffoldedMigrations: _generatedMigration_v1);
var generatedMigration_v2 = new MigrationScaffolder(migrator.Configuration).Scaffold("V2");
var migrationsConfiguration =
CreateMigrationsConfiguration<TContextV2>(
scaffoldedMigrations: new[] { _generatedMigration_v1, generatedMigration_v2 });
migrationsConfiguration.SetSqlGenerator(DbProviders.Sql, _upVerifier);
migrationsConfiguration.SetSqlGenerator(DbProviders.SqlCe, _upVerifier);
new DbMigrator(migrationsConfiguration).Update();
// Bring up via generated
CreateMigrator<TContextV2>(
scaffoldedMigrations: new[] { _generatedMigration_v1, generatedMigration_v2 })
.Update();
migrationsConfiguration =
CreateMigrationsConfiguration<TContextV2>(
scaffoldedMigrations: new[] { _generatedMigration_v1, generatedMigration_v2 });
migrationsConfiguration.SetSqlGenerator(DbProviders.Sql, _downVerifier);
migrationsConfiguration.SetSqlGenerator(DbProviders.SqlCe, _downVerifier);
new DbMigrator(migrationsConfiguration).Update(_generatedMigration_v1.MigrationId);
}
private void ResetDatabaseToV1()
{
ResetDatabase();
var migrator = CreateMigrator<TContextV1>();
_generatedMigration_v1 = new MigrationScaffolder(migrator.Configuration).Scaffold("V1");
CreateMigrator<TContextV1>(scaffoldedMigrations: _generatedMigration_v1).Update();
}
protected abstract void VerifyUpOperations(IEnumerable<MigrationOperation> migrationOperations);
protected abstract void VerifyDownOperations(IEnumerable<MigrationOperation> migrationOperations);
private class SqlInterceptor : MigrationSqlGenerator
{
private static readonly IList<Type> _excludedTypes
= new List<Type>
{
typeof(HistoryOperation)
};
private readonly Action<IEnumerable<MigrationOperation>> _verifyAction;
private bool _wasCalled;
public SqlInterceptor(Action<IEnumerable<MigrationOperation>> verifyAction)
{
_verifyAction = verifyAction;
}
public override IEnumerable<MigrationStatement> Generate(
IEnumerable<MigrationOperation> migrationOperations, string providerManifestToken)
{
_wasCalled = true;
_verifyAction(migrationOperations.Where(mo => !_excludedTypes.Contains(mo.GetType())).ToList());
return Enumerable.Empty<MigrationStatement>();
}
public bool WasCalled()
{
var wasCalled = _wasCalled;
_wasCalled = false;
return wasCalled;
}
}
}
#region Model stubs
public class AutoAndGenerateContext_v1 : DbContext
{
public AutoAndGenerateContext_v1()
: base("AutoAndGenerateContext_v1")
{
}
}
public class AutoAndGenerateContext_v2 : DbContext
{
public AutoAndGenerateContext_v2()
: base("AutoAndGenerateContext_v2")
{
}
}
#endregion
}
|