1 #region Copyright ©  2003-2008 Richard Beauchamp <rbeauchamp@gmail.com>
   2 
   3 /*
   4 * DomainObjects for .NET
   5 * Copyright ©  2003-2008 Richard Beauchamp
   6 *
   7 * This library is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU Lesser General Public
   9 * License as published by the Free Software Foundation; either
  10 * version 2.1 of the License, or (at your option) any later version.
  11 *
  12 * This library is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15 * Lesser General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU Lesser General Public
  18 * License along with this library; if not, write to the Free Software
  19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  20 */
  21 
  22 #endregion
  23 
  24 using System;
  25 using System.Collections.Generic;
  26 using DomainObjects.Facade.Command;
  27 using DomainObjects.Facade.Domain;
  28 using DomainObjects.Facade.Test;
  29 using DomainObjects.Test.Domain;
  30 using DomainObjects.Test.TestType.Service;
  31 using NUnit.Framework;
  32 
  33 namespace DomainObjects.Test.TestFixture
  34 {
  35   /// <summary>
  36   /// Test that DomainObjects makes appropriate calls to the
  37   /// callback interfaces ITransactionAware, ITransactionSetAware,
  38   /// and IReconstructionAware.
  39   /// </summary>
  40   [TestFixture]
  41   public class CallbackTests : DomainObjectsTestFixture
  42   {
  43     #region ITransactionAware callback interface tests
  44 
  45     [Test]
  46     public void BeforeAndAfterCommitOnBoundObject()
  47     {
  48       Product newProduct = CreateProduct();
  49       PersistenceFacade.Persist(newProduct);
  50       Assert.IsTrue(newProduct.BeforeCommitWasCalled, "BeforeCommit() was called.");
  51       Assert.IsTrue(newProduct.AfterCommitWasCalled, "AfterCommit() was called.");
  52     }
  53 
  54     #endregion
  55 
  56 
  57     #region IExecutionAware callback interface tests
  58 
  59     [Test]
  60     public void BeforeAndAfterExecutionTest()
  61     {
  62       Product newProduct = CreateProduct();
  63       PersistenceFacade.Persist(newProduct);
  64       Assert.IsTrue(newProduct.BeforeExecuteAllSentencesWasCalled, "BeforeExecuteAllSentences() was called.");
  65       Assert.IsTrue(newProduct.AfterExecuteAllSentencesWasCalled, "AfterExecuteAllSentences() was called.");
  66       Assert.IsTrue(newProduct.AfterExecuteAndCommitWasCalled, "AfterExecuteAndCommit() was called.");
  67       Assert.IsTrue(newProduct.BeforeExecuteWasCalled, "BeforeExecute() was called.");
  68       Assert.IsTrue(newProduct.AfterExecuteWasCalled, "AfterExecute() was called.");
  69 
  70       newProduct.Name = "Update the Product";
  71       PersistenceFacade.Persist(newProduct);
  72 
  73       newProduct.Name = "RollbackMe";
  74 
  75       try
  76       {
  77         PersistenceFacade.Persist(newProduct);
  78       }
  79       catch
  80       {
  81       }
  82 
  83       ClearAppDomainAndContextCache();
  84 
  85       Product product = QueryFacade.FindObjectByPrimaryKey<Product>(newProduct.PrimaryKey);
  86 
  87       Assert.AreEqual("Update the Product", product.Name, "The name is 'Update the Product'. The last execution was cancelled");
  88     }
  89 
  90     #endregion
  91 
  92     #region IReconstructionAware callback interface tests
  93 
  94     [Test]
  95     public void OnAfterReconstructionCalled()
  96     {
  97       // The class Product implements the IReconstructionAware interface.
  98       // Setup test by creating and persisting a Product instance.
  99       Product newProduct = CreateProduct();
 100       PersistenceFacade.Persist(newProduct);
 101 
 102       // Get the Product primary key for later use.
 103       object productPrimaryKey = newProduct.PrimaryKey;
 104 
 105       // Clear the cache so that the Product instance will
 106       // be reconstructed from the database rather than being
 107       // retrieved from the cache.
 108       ClearAppDomainAndContextCache();
 109 
 110       // Query for the product so that DomainObjects retrieves the instance from
 111       // the database and calls OnAfterReconstruction().
 112       Product productFromDb = Query.FindObjectByPrimaryKey<Product>(productPrimaryKey);
 113       Assert.IsTrue(productFromDb.OnAfterReconstructionWasCalled, "OnAfterReconstruction() was called.");
 114     }
 115 
 116     /// <summary>
 117     /// Reproduces the bug '[ 1522191 ] OnAfterReconstructor Issue'.
 118     /// Tests the if a query occurs when OnAfterReconstruction is called,
 119     /// DomainObjects retrieves the results without throwing a 'System.InvalidOperationException'
 120     /// because 'There is already an open DataReader associated with this Command which must be closed first.'
 121     /// </summary>
 122     [Test]
 123     public void QueryDuringOnAfterReconstructionDoesNotCauseException()
 124     {
 125       ProductCategory productCategory = new ProductCategory("ProductCategoryName", "ProductCategoryDescription").Manage<ProductCategory>();
 126       Product newProduct1 = new Product(productCategory, "ProductName1").Manage<Product>();
 127       Product newProduct2 = new Product(productCategory, "ProductName2").Manage<Product>();
 128 
 129       PersistenceFacade.Persist(newProduct1, newProduct2, productCategory);
 130       Key productCategoryPrimaryKey = productCategory.PrimaryKey;
 131       ClearAppDomainAndContextCache();
 132       Criteria criteria = new Criteria();
 133       criteria.AddEqualTo(Types.Product.Field._productCategoryId, productCategoryPrimaryKey[0]);
 134       List<Product> productsFromDb = QueryFacade.FindObjectSet<Product>(criteria);
 135       foreach (Product productFromDb in productsFromDb)
 136       {
 137         Assert.IsTrue(productFromDb.OnAfterReconstructionWasCalled, "OnAfterReconstruction() was called.");
 138       }
 139     }
 140 
 141     #endregion
 142 
 143 
 144     #region ITransactionSetAware callback interface tests
 145 
 146     [Test]
 147     public void BeforeAndAfterCommitOnITransactionSetAware()
 148     {
 149       Product newProduct = CreateProduct();
 150       PersistenceFacade.Persist(newProduct);
 151       Assert.IsTrue(!TransactionSetAware.BeforeCommitCalled, "BeforeCommit() was not called.");
 152       Assert.IsTrue(!TransactionSetAware.AfterCommitCalled, "AfterCommit() was not called.");
 153 
 154       // TransactionalAwareService defines the
 155       // TransactionAttribute(TransactionOption transactionOption, Type transactionAwareType) attribute
 156       Product newProduct2 = CreateProduct();
 157       TransactionSetAwareService.Instance.Persist(newProduct2);
 158       Assert.IsTrue(TransactionSetAware.BeforeCommitCalled, "BeforeCommit() was called.");
 159       Assert.IsTrue(TransactionSetAware.AfterCommitCalled, "AfterCommit() was called.");
 160     }
 161 
 162     [Test]
 163     public void OnAbortCalledOnITransactionSetAware()
 164     {
 165       try
 166       {
 167         TransactionSetAwareService.Instance.ThrowException();
 168       }
 169       catch
 170       {
 171         // nothing to do
 172       }
 173       Assert.IsTrue(TransactionSetAware.OnAbortCalled, "OnAbort() was called.");
 174     }
 175 
 176     #endregion
 177 
 178 
 179     private static Product CreateProduct()
 180     {
 181       Product product = new Product(GetProductCategory(1), DateTime.Now.Ticks.ToString()).Manage<Product>();
 182       product.Name = "CallbackTests Product";
 183       product.IsSelloutProduct = true;
 184       product.MinimumStock = 100;
 185       product.OrderedUnits = 17;
 186       product.PricePerUnit = 0.45M;
 187       product.CurrentStock = 234;
 188       product.Unit = "bottle";
 189       return product.Manage<Product>();
 190     }
 191 
 192     private static ProductCategory GetProductCategory(int primaryKey)
 193     {
 194       return Query.FindObjectByPrimaryKey<ProductCategory>(primaryKey);
 195     }
 196   }
 197 }