Skip to content
This repository has been archived by the owner on Dec 20, 2018. It is now read-only.

Moved POCOs to EF and fixed tests #378

Closed
wants to merge 4 commits into from
Closed

Moved POCOs to EF and fixed tests #378

wants to merge 4 commits into from

Conversation

suhasj
Copy link
Contributor

@suhasj suhasj commented Feb 27, 2015

@HaoK I moved the POCOs to Identity.EF. The Identity.Test and Identity.InMemory.Test broke due to this change since they did not reference Identity.EF. Now we could either duplicate the code in the tests or reference the assembly and include the namespace. In addition the UserManagerTestBase is shared so that has to updated also. I choose to reference the assembly as this seems more cleaner. I made sure we reference only the POCOs and nothing else. Let me know if there is a better way of doing this.

/cc @divega

You can skip the nitpick feedback for this PR

@ghost ghost added the cla-not-required label Feb 27, 2015
@HaoK
Copy link
Member

HaoK commented Feb 27, 2015

Nah, its a bad idea to add EF dependencies, just copy the pocos into the shared test code and rename them for the tests

@suhasj
Copy link
Contributor Author

suhasj commented Feb 27, 2015

In doing so, I have replicate the code in UserManagerTestBase for InMemory.Test project since it uses the IdentityUser object and that is a lot of duplication. Is that the right way ?

@HaoK
Copy link
Member

HaoK commented Feb 27, 2015

There should be no replication other than copying the pocos from Core to the Shared Test code along side user manager test base with a new name for the pocos

@suhasj
Copy link
Contributor Author

suhasj commented Feb 27, 2015

Ok let me see if the amount of duplicated code will be difficult to maintain in the future. I can reason out accordingly after that

@suhasj
Copy link
Contributor Author

suhasj commented Feb 27, 2015

Now if I duplicate the POCOs in the Shared folder and make UserManagerTestBase use them, the SqlStoreBase complains since it uses UserManagerTestBase with IdentityUser from Identity.EF. If I make all the test projects to use the POCOs in the shared folder, then we need to maintain them along with the POCOs in the source. My concern is that if we forget to update them then the tests will pass incorrectly.

@HaoK
Copy link
Member

HaoK commented Feb 28, 2015

Or maybe just move the IdentityUser classes to the new shared code stuff, so both EF and tests can depend on it safely.

@HaoK
Copy link
Member

HaoK commented Feb 28, 2015

Another route could be to look at what the tests are doing to access the pocos directly and instead replace them with calls to identity, which might let you remove the IdentityUser constraint entirely

@suhasj
Copy link
Contributor Author

suhasj commented Mar 2, 2015

Sure the second option might be an easy option. Let me try that out

@suhasj
Copy link
Contributor Author

suhasj commented Mar 3, 2015

@HaoK @divega

Updated with changes

  • UserManagerTestBase now is agnostic to user model and gets all attributes using manager apis.
  • Identity POCOs in Shared folder to be used by InMemory and Core tests
  • updated samples

Question

  • New extension method on ServiceCollection AddIdentityWithTestPocos which is used only in test because it uses the Shared Pocos while the one is source uses EF ones. Instead of this should i move the IdentityBuilderTests and IdentityOptionsTests to EF ? I would want to go with move option

{
public static class IdentityServiceCollectionExtensions
{
public static IdentityBuilder AddIdentity(this IServiceCollection services)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting that these overload now moves here because the typed moved and hence they are tied to EF. I think it would probably be better to get rid of them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed and updated

@suhasj
Copy link
Contributor Author

suhasj commented Mar 3, 2015

Also one important feedback i need to getting username synchronously inside a Linq queries. For example
mgr.GetUserNameAsync(u).Result in https://github.com/aspnet/Identity/pull/378/files#diff-bc862db146cf4a686c23d4fb0676c99eR584. The reason for doing this is that the Linq query cannot be async. Let me know if this is something that is not recommended.

The workaround is to have a sync method on the UserManagerTestBase class which returns different user attributes. For example GetUserId(user). This is abstract on the base and is implemented by the concrete test classes

/// <summary>
/// Navigation property for users in the role
/// </summary>
public virtual ICollection<IdentityUserRole<TKey>> Roles { get; private set; } = new List<IdentityUserRole<TKey>>();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will private create issues with reflection on Mono?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need navigation properties on the shared test pocos?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True but I wanted to have parity with the Pocos in the source. The navigation property can be deleted in test pocos

@divega for the private thing, the issue is fixed in the latest version of Mono. But should we revert it to protected ? Do we foresee users overriding this property considering it is a navigation property ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its not about parity, the EF pocos are EF specific, if the navigation properties are not needed for the tests, they shouldn't be there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so the navigation properties are needed since the InMemory tests makes use of them. I need to keep them

@divega
Copy link

divega commented Mar 4, 2015

mgr.GetUserNameAsync(u).Result in https://github.com/aspnet/Identity/pull/378/files#diff-bc862db146cf4a686c23d4fb0676c99eR584. The reason for doing this is that the Linq query cannot be async. Let me know if this is something that is not recommended.

Can't you do this?

var userName = await mgr.GetUserNameAsync(u);
Assert.Null(mgr.Users.FirstOrDefault(u => userName == "bogus"));

@divega
Copy link

divega commented Mar 4, 2015

New extension method on ServiceCollection AddIdentityWithTestPocos which is used only in test because it uses the Shared Pocos while the one is source uses EF ones. Instead of this should i move the IdentityBuilderTests and IdentityOptionsTests to EF ? I would want to go with move option

I don't understand this question, and I couldn't find the method right now. Did you already remove it? Were these test be independent of the provider?

@@ -65,6 +67,152 @@ public void DropDatabaseStart()
IdentityResultAssert.IsSuccess(await userManager.DeleteAsync(user));
}

[Fact]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these new tests or copied tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are new ones I added to test if navigation properties work when used with Include on dbContext

@suhasj
Copy link
Contributor Author

suhasj commented Mar 4, 2015

@divega Using a variable ! so obvious. To answer the second question, yes the class no longer exists so it is fine

@suhasj
Copy link
Contributor Author

suhasj commented Mar 4, 2015

@divega Now I recall that I did not use the variable since i need to use the object inside the Where clause. So var userName = await mgr.GetUserNameAsync(u); would not work since u is to be got from the lambda. The workaround I see is to use a foreach loop instead of Where which is not clean either.

@divega
Copy link

divega commented Mar 4, 2015

Ah, I missed that. Sorry.

@suhasj
Copy link
Contributor Author

suhasj commented Mar 5, 2015

Updated with feedback

  • Removed InMemoryUser and ApplicationUser. Identity.Test and IdentityInMemory.Test refer to TestUser only
  • GetPasswordHash an abstract method on UserManagerTestBase
  • CreateTestUser now takes namePrefix instead of username
  • CreateTestRole does not take a namePrefix since most test need a expected rolename for further assertions.

@suhasj suhasj changed the title [Feedback PR] Moved POCOs to EF and fixed tests Moved POCOs to EF and fixed tests Mar 12, 2015
@suhasj
Copy link
Contributor Author

suhasj commented Mar 12, 2015

@HaoK @divega

Removing the feedback tag. I have addressed all feedback so wanted to make sure it is ready to check in

@divega
Copy link

divega commented Mar 12, 2015

I'll take another look later today.

@HaoK
Copy link
Member

HaoK commented Mar 13, 2015

You might want to rebase since I added some functionals in InMemory yesterday, but otherwise looks :shipit: to me

@suhasj
Copy link
Contributor Author

suhasj commented Mar 18, 2015

@divega pinging a reminder

});

var userManager = builder.ApplicationServices.GetRequiredService<UserManager<IdentityUser>>();
var dbContext = builder.ApplicationServices.GetRequiredService<IdentityDbContext>();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DbContext is IDisposable. Please use using even if doesn't seem needed right now.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, scratch that. I see now that you don't control the lifetime of this one directly.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However this still doesn't seem right. When will the context get disposed? I assume you copied this pattern from other tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am assuming you are worried how the database is cleared ? There is a test DropDatabaseStart that is marked with lowest priority that will delete the database after all the tests in the class have run. This class existed all the way long. I have only added more tests that's all. Regarding the object, since it is created in the scope of the test, then it should be disposed at the end of it. If adding a using statement for DBContext is the recommended practice then sure I can update that but will have to do it in other tests as well

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am more worried about the risk of tests leaking resources, e.g. connections, or even memory depending how (well) the DI container implementation works and what we do in the tests.

@suhasj
Copy link
Contributor Author

suhasj commented Mar 23, 2015

Rebased with latest and remove all instances of .Result in the UserManagerTestBase. Added the predicate to compare user/roles names. Needed to add a contains flag since has two asserts that needed to test part of user/roles names.

Also noop for IQueryable tests is the managers do not support them


protected abstract TRole CreateTestRole(string roleName = "");

protected abstract Expression<Func<TUser, bool>> UserNamePredicate(string userName, bool contains = false);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I would rather simplify the tests to just succeed with simple equality and get rid of the contains flag on both predicates.
  2. Contains is not the same as StartsWith.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than that, I think we are very close.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah Contains != StartsWith, should be StartsWith

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't simplify the tests to just do equality since we aren't cleaning up the database, so a lot of the tests use the same username prefix, like "test", and we only drop/recreate the database once per run. Rather than trying to manually maintain user name uniqueness, I went with the approach of randomizing the names instead by always jamming on a guid, and then doing StratsWith instead of strict equality.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We were doing name + guid so I presumed Contains would still be valid check instead of StartWith considering we are looking if part of the string is present. I'll revert back to StartsWith it is just that I have to now maintain the original randomized username and pass it exactly to the predicate

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am ok with having StartsWith checks if we can't have just do equality. But let's then split this in 4 simple predicate methods without any flags: GetUserNameEqualsPredicate(string), GetUserNameStartsWithPredicate(string), GetRoleNameEqualsPredicate(string), GetRoleNameStartsWithPredicate(string).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the four predicates and restored the test to original assert statements

@suhasj
Copy link
Contributor Author

suhasj commented Mar 23, 2015

Updated with 2 additional predicates to compare StartsWith for user/role name

  • Some changes you might be interested in predicates
  • queryable tests 1 and 2

@ajcvickers made changes to EF for mapping. Should I rebase and send another PR to see if that works with these changes ?

@suhasj
Copy link
Contributor Author

suhasj commented Mar 24, 2015

I rebased it to latest EF which had renaming for mapping in OnModel creating. I have updated the IdentityDbContext with the latest changes

@ajcvickers can you please specifically review changes to IdentityDbContext

}
Assert.Equal(roles.Count, manager.Roles.Count(RoleNameStartsWithPredicate("CanQuerableRolesTest")));
var r1 = manager.Roles.FirstOrDefault(RoleNameStartsWithPredicate("CanQuerableRolesTest1"));
Assert.Equal(roles[1], r1);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have a negative assert as in the Users test and standardize on the same test data generation pattern?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure I updated it and role name are done the same way as usernames.

@ajcvickers
Copy link
Contributor

IdentityDbContext changes look fine.

@divega
Copy link

divega commented Mar 24, 2015

:shipit: to get it on beta4. We can address any outstanding test issues later.

@suhasj
Copy link
Contributor Author

suhasj commented Mar 24, 2015

thanks to everybody for patiently reviewing this

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants