From 9a1f0347c0644f765ca444a89a44a033f3b07f08 Mon Sep 17 00:00:00 2001 From: tmont Date: Thu, 10 Feb 2011 21:04:13 +0000 Subject: [PATCH] * tests for user provider * username is no longer required * added ip address property to user --- .../ICurrentUserProvider.cs | 7 ++ Src/VideoGameQuotes.Api/Mappings/User.hbm.xml | 3 +- Src/VideoGameQuotes.Api/Mappings/Vote.hbm.xml | 2 +- .../Persistence/IUserRepository.cs | 12 ++- .../Persistence/UserService.cs | 9 ++- Src/VideoGameQuotes.Api/User.cs | 1 + Src/VideoGameQuotes.Web/Global.asax.cs | 2 +- ...rovider.cs => SessionBasedUserProvider.cs} | 12 +-- .../VideoGameQuotes.Web.csproj | 2 +- .../VideoGameQuotes.Api.Tests.csproj | 3 + .../Properties/AssemblyInfo.cs | 36 +++++++++ .../UserProviderTests.cs | 48 ++++++++++++ .../VideoGameQuotes.Web.Tests.csproj | 77 +++++++++++++++++++ VideoGameQuotes.sln | 6 ++ 14 files changed, 208 insertions(+), 12 deletions(-) rename Src/VideoGameQuotes.Web/Security/{UserProvider.cs => SessionBasedUserProvider.cs} (65%) create mode 100644 Tests/VideoGameQuotes.Web.Tests/Properties/AssemblyInfo.cs create mode 100644 Tests/VideoGameQuotes.Web.Tests/UserProviderTests.cs create mode 100644 Tests/VideoGameQuotes.Web.Tests/VideoGameQuotes.Web.Tests.csproj diff --git a/Src/VideoGameQuotes.Api/ICurrentUserProvider.cs b/Src/VideoGameQuotes.Api/ICurrentUserProvider.cs index 545591a..1cd2b25 100644 --- a/Src/VideoGameQuotes.Api/ICurrentUserProvider.cs +++ b/Src/VideoGameQuotes.Api/ICurrentUserProvider.cs @@ -1,7 +1,14 @@ using JetBrains.Annotations; namespace VideoGameQuotes.Api { + /// + /// Provides an interface for identifying the current user + /// public interface ICurrentUserProvider { + /// + /// Returns the user currently performing actions on the site, or null + /// if the user cannot be identified + /// [CanBeNull] User CurrentUser { get; } } diff --git a/Src/VideoGameQuotes.Api/Mappings/User.hbm.xml b/Src/VideoGameQuotes.Api/Mappings/User.hbm.xml index f63b269..80bd4a9 100644 --- a/Src/VideoGameQuotes.Api/Mappings/User.hbm.xml +++ b/Src/VideoGameQuotes.Api/Mappings/User.hbm.xml @@ -6,7 +6,8 @@ - + + diff --git a/Src/VideoGameQuotes.Api/Mappings/Vote.hbm.xml b/Src/VideoGameQuotes.Api/Mappings/Vote.hbm.xml index caab5bb..9ce94d9 100644 --- a/Src/VideoGameQuotes.Api/Mappings/Vote.hbm.xml +++ b/Src/VideoGameQuotes.Api/Mappings/Vote.hbm.xml @@ -7,7 +7,7 @@ - + diff --git a/Src/VideoGameQuotes.Api/Persistence/IUserRepository.cs b/Src/VideoGameQuotes.Api/Persistence/IUserRepository.cs index 4c097e3..979d64d 100644 --- a/Src/VideoGameQuotes.Api/Persistence/IUserRepository.cs +++ b/Src/VideoGameQuotes.Api/Persistence/IUserRepository.cs @@ -1,11 +1,17 @@ -using System.Linq; +using System; +using System.Linq; +using JetBrains.Annotations; using NHibernate; using Portoa.NHibernate; using Portoa.Persistence; namespace VideoGameQuotes.Api.Persistence { public interface IUserRepository : IRepository { + [CanBeNull] User FindByUsername(string name); + + [CanBeNull] + User FindByIpAddress(string ipAddress); } public class UserRepository : NHibernateRepository, IUserRepository { @@ -14,5 +20,9 @@ namespace VideoGameQuotes.Api.Persistence { public User FindByUsername(string name) { return Records.FirstOrDefault(user => user.Username == name); } + + public User FindByIpAddress(string ipAddress) { + return Records.FirstOrDefault(user => user.IpAddress == ipAddress); + } } } \ No newline at end of file diff --git a/Src/VideoGameQuotes.Api/Persistence/UserService.cs b/Src/VideoGameQuotes.Api/Persistence/UserService.cs index e1b08aa..30324ee 100644 --- a/Src/VideoGameQuotes.Api/Persistence/UserService.cs +++ b/Src/VideoGameQuotes.Api/Persistence/UserService.cs @@ -1,10 +1,12 @@ -using Portoa.Persistence; +using System; +using Portoa.Persistence; namespace VideoGameQuotes.Api.Persistence { public interface IUserService { User Save(User user); User FindByUsername(string name); + User FindByIpAddress(string ipAddress); } public class UserService : IUserService { @@ -23,5 +25,10 @@ namespace VideoGameQuotes.Api.Persistence { public User FindByUsername(string name) { return repository.FindByUsername(name); } + + [UnitOfWork] + public User FindByIpAddress(string ipAddress) { + return repository.FindByIpAddress(ipAddress); + } } } \ No newline at end of file diff --git a/Src/VideoGameQuotes.Api/User.cs b/Src/VideoGameQuotes.Api/User.cs index f1cdb5b..2eb310c 100644 --- a/Src/VideoGameQuotes.Api/User.cs +++ b/Src/VideoGameQuotes.Api/User.cs @@ -13,6 +13,7 @@ namespace VideoGameQuotes.Api { public virtual DateTime Created { get; set; } public virtual string Username { get; set; } + public virtual string IpAddress { get; set; } public virtual UserGroup Group { get; set; } public virtual void ChangePassword([DoNotLog]string newPassword) { diff --git a/Src/VideoGameQuotes.Web/Global.asax.cs b/Src/VideoGameQuotes.Web/Global.asax.cs index a9e6859..31dd144 100644 --- a/Src/VideoGameQuotes.Web/Global.asax.cs +++ b/Src/VideoGameQuotes.Web/Global.asax.cs @@ -18,7 +18,7 @@ namespace VideoGameQuotes.Web { Container .AddNewExtension() - .RegisterType() + .RegisterType() .RegisterType() .RegisterType(); } diff --git a/Src/VideoGameQuotes.Web/Security/UserProvider.cs b/Src/VideoGameQuotes.Web/Security/SessionBasedUserProvider.cs similarity index 65% rename from Src/VideoGameQuotes.Web/Security/UserProvider.cs rename to Src/VideoGameQuotes.Web/Security/SessionBasedUserProvider.cs index 7ee0d00..820d396 100644 --- a/Src/VideoGameQuotes.Web/Security/UserProvider.cs +++ b/Src/VideoGameQuotes.Web/Security/SessionBasedUserProvider.cs @@ -4,12 +4,12 @@ using VideoGameQuotes.Api; using VideoGameQuotes.Api.Persistence; namespace VideoGameQuotes.Web.Security { - public class UserProvider : ICurrentUserProvider { + public class SessionBasedUserProvider : ICurrentUserProvider { private readonly IUserService userService; private readonly ISessionStore sessionStore; private readonly HttpContextBase httpContext; - public UserProvider(IUserService userService, ISessionStore sessionStore, HttpContextBase httpContext) { + public SessionBasedUserProvider(IUserService userService, ISessionStore sessionStore, HttpContextBase httpContext) { this.userService = userService; this.sessionStore = sessionStore; this.httpContext = httpContext; @@ -21,15 +21,15 @@ namespace VideoGameQuotes.Web.Security { if (user == null) { //identify user by IP address - var username = httpContext.Request.UserHostAddress; - if (string.IsNullOrEmpty(username)) { + var ipAddress = httpContext.Request.UserHostAddress; + if (string.IsNullOrEmpty(ipAddress)) { return null; } - user = userService.FindByUsername(username); + user = userService.FindByIpAddress(ipAddress); if (user == null) { user = new User { - Username = username, + IpAddress = ipAddress, Group = UserGroup.User }; diff --git a/Src/VideoGameQuotes.Web/VideoGameQuotes.Web.csproj b/Src/VideoGameQuotes.Web/VideoGameQuotes.Web.csproj index 451a467..23ec8fc 100644 --- a/Src/VideoGameQuotes.Web/VideoGameQuotes.Web.csproj +++ b/Src/VideoGameQuotes.Web/VideoGameQuotes.Web.csproj @@ -86,7 +86,7 @@ Default.aspx ASPXCodeBehind - + Global.asax diff --git a/Tests/VideoGameQuotes.Api.Tests/VideoGameQuotes.Api.Tests.csproj b/Tests/VideoGameQuotes.Api.Tests/VideoGameQuotes.Api.Tests.csproj index 8ab8572..17f2a3c 100644 --- a/Tests/VideoGameQuotes.Api.Tests/VideoGameQuotes.Api.Tests.csproj +++ b/Tests/VideoGameQuotes.Api.Tests/VideoGameQuotes.Api.Tests.csproj @@ -34,6 +34,9 @@ ..\..\Lib\log4net.dll + + ..\..\Lib\Moq.dll + ..\..\Lib\MySql.Data.dll diff --git a/Tests/VideoGameQuotes.Web.Tests/Properties/AssemblyInfo.cs b/Tests/VideoGameQuotes.Web.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d95211e --- /dev/null +++ b/Tests/VideoGameQuotes.Web.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("VideoGameQuotes.Web.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("VideoGameQuotes.Web.Tests")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("2e52aa26-c170-44ad-801f-3ee9d6aa3fcd")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Tests/VideoGameQuotes.Web.Tests/UserProviderTests.cs b/Tests/VideoGameQuotes.Web.Tests/UserProviderTests.cs new file mode 100644 index 0000000..831a088 --- /dev/null +++ b/Tests/VideoGameQuotes.Web.Tests/UserProviderTests.cs @@ -0,0 +1,48 @@ +using System.Web; +using Moq; +using NUnit.Framework; +using Portoa.Web.Session; +using VideoGameQuotes.Api; +using VideoGameQuotes.Api.Persistence; +using VideoGameQuotes.Web.Security; + +namespace VideoGameQuotes.Web.Tests { + [TestFixture] + public class UserProviderTests { + [Test] + public void Should_use_user_in_session_store() { + var session = new Mock(); + var user = new User(); + session.SetupGet(s => s["user"]).Returns(user).Verifiable(); + + var userProvider = new SessionBasedUserProvider(new Mock().Object, session.Object, new Mock().Object); + + Assert.That(userProvider.CurrentUser, Is.EqualTo(user)); + session.VerifyAll(); + } + + [Test] + public void Should_identify_user_using_ip_address() { + var session = new Mock(); + session.SetupGet(s => s["user"]).Returns(null); + + var httpContext = new Mock(); + var httpRequest = new Mock(); + httpRequest.SetupGet(req => req.UserHostAddress).Returns("10.4.60.120"); + httpContext.SetupGet(ctx => ctx.Request).Returns(httpRequest.Object); + + + var userService = new Mock(); + userService.Setup(service => service.Save(It.IsAny())).Callback(user => { + Assert.That(user, Is.Not.Null); + Assert.That(user.Username, Is.Null); + Assert.That(user.IpAddress, Is.EqualTo("10.4.60.120")); + Assert.That(user.Group, Is.EqualTo(UserGroup.User)); + }).Returns(new User { Id = 1 }); + + var userProvider = new SessionBasedUserProvider(userService.Object, session.Object, httpContext.Object); + + Assert.That(userProvider.CurrentUser, Is.EqualTo(new User { Id = 1 })); + } + } +} \ No newline at end of file diff --git a/Tests/VideoGameQuotes.Web.Tests/VideoGameQuotes.Web.Tests.csproj b/Tests/VideoGameQuotes.Web.Tests/VideoGameQuotes.Web.Tests.csproj new file mode 100644 index 0000000..9f8ee09 --- /dev/null +++ b/Tests/VideoGameQuotes.Web.Tests/VideoGameQuotes.Web.Tests.csproj @@ -0,0 +1,77 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {5787E8CA-072D-4231-B34A-B4C92BEEA3E7} + Library + Properties + VideoGameQuotes.Web.Tests + VideoGameQuotes.Web.Tests + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\Lib\Moq.dll + + + ..\..\Lib\nunit.framework.dll + + + ..\..\Lib\Portoa.dll + + + ..\..\Lib\Portoa.Web.dll + + + + + + + + + + + + + + + + + {329FAB1F-A18D-4B7B-9E3C-A0C157E55503} + VideoGameQuotes.Api + + + {5D576303-EEB3-409B-80E2-FC221C23D7BF} + VideoGameQuotes.Web + + + + + \ No newline at end of file diff --git a/VideoGameQuotes.sln b/VideoGameQuotes.sln index a4b4d26..2de3567 100644 --- a/VideoGameQuotes.sln +++ b/VideoGameQuotes.sln @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VideoGameQuotes.Api.Tests", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VideoGameQuotes.Web", "Src\VideoGameQuotes.Web\VideoGameQuotes.Web.csproj", "{5D576303-EEB3-409B-80E2-FC221C23D7BF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VideoGameQuotes.Web.Tests", "Tests\VideoGameQuotes.Web.Tests\VideoGameQuotes.Web.Tests.csproj", "{5787E8CA-072D-4231-B34A-B4C92BEEA3E7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -25,6 +27,10 @@ Global {5D576303-EEB3-409B-80E2-FC221C23D7BF}.Debug|Any CPU.Build.0 = Debug|Any CPU {5D576303-EEB3-409B-80E2-FC221C23D7BF}.Release|Any CPU.ActiveCfg = Release|Any CPU {5D576303-EEB3-409B-80E2-FC221C23D7BF}.Release|Any CPU.Build.0 = Release|Any CPU + {5787E8CA-072D-4231-B34A-B4C92BEEA3E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5787E8CA-072D-4231-B34A-B4C92BEEA3E7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5787E8CA-072D-4231-B34A-B4C92BEEA3E7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5787E8CA-072D-4231-B34A-B4C92BEEA3E7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE