Cucumber: Why do I fail to pass Java enum value? - cucumber

Given the following code:
public enum Roles {
ADMIN("admin"),
OPERATOR("operator"),
SYSTEM_ADMIN("system-admin"),
SYSTEM_VIEWER("system-viewer"),
TENANT_ADMIN("admin"),
TENANT_OPERATOR("operator"),
TENANT_VIEWER("viewer");
private String role;
private Roles(String role) { this.role = role; }
public String getRole() {
return role;
}
}
public class TenantMapping {
private String tenant;
private Roles role;
public TenantMapping(String tenant, Roles role) {
super();
this.tenant = tenant;
this.role = role;
}
//accessors
}
Scenario: Create new users
When REST Create new user "system_systemuser" with tenants list
| system | SYSTEM_ADMIN |
#When("^REST Create new user \"(.*)\" with tenants list$")
public void createNewUser(String newUsername, Map<String, Roles> tenantsMap) {
try {
List<TenantMapping> tenantMappingsList = new ArrayList<>();
tenantsMap.forEach((key, value) -> tenantMappingsList.add(new TenantMapping(key, value)));
....
}
usersRest.json maybe relevant fragment:
"tenant_mappings": [
{
"tenant": "system",
"role": "system-admin"
}
...
]
When I run the scenario I get:
java.lang.AssertionError: 13:09:43: Failed to get the Object from
usersRest.json file
com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not
construct instance of
com.rest.testhandlers.restassured.system.users.enums.Roles from String
value 'system-admin': value not one of declared Enum instance names:
[ADMIN, OPERATOR, SYSTEM_ADMIN, SYSTEM_VIEWER, TENANT_ADMIN,
TENANT_OPERATOR, TENANT_VIEWER]
and when I try:
Scenario: Create new users
When REST Create new user "system_systemuser" with tenants list
| system | system-admin |
I get:
cucumber.deps.com.thoughtworks.xstream.converters.ConversionException:
Couldn't convert system-admin to
com.rest.testhandlers.restassured.system.users.enums.Roles. Legal
values are [ADMIN, OPERATOR, SYSTEM_ADMIN, SYSTEM_VIEWER,
TENANT_ADMIN, TENANT_OPERATOR, TENANT_VIEWER]
Why?

My guess is that there is some attempt at casting from string to emum here which is causing the first issue?
In the first attempt you are passing the correct capitalised ENUM value in your Gherkin datatable, but in the tenantMapping constructor you decLare you are passing a Roles ENUM object (containing all values etc.) and but actually pass a String from the dataTable with value 'SYSTEM_ADMIN ':
public TenantMapping(String tenant, **Roles role**) {
super();
this.tenant = tenant;
this.role = role;
}
Perhaps you should instead call the ENUM constructor in this function using the (uppercase) role value and then ask the enum for its current role (lowercase) and save that in your mapping:
public TenantMapping(String tenant, **String role**) {
super();
this.tenant = tenant;
// better to use some case switch to cover all options in your solution
if (role.equals("SYSTEM_ADMIN"){Roles.SYSTEM_ADMIN;}
// the Roles Enum calls its private constructor and sets current 'role' value
this.role = Roles.getRole();
}

I get:
cucumber.deps.com.thoughtworks.xstream.converters.ConversionException: Couldn't convert system-admin to com.rest.testhandlers.restassured.system.users.enums.Roles. Legal values are [ADMIN, OPERATOR, SYSTEM_ADMIN, SYSTEM_VIEWER, TENANT_ADMIN, TENANT_OPERATOR, TENANT_VIEWER]
Why?
While you do create your enum using the lower case name ADMIN("admin"), neither Jackson nor XStream knows that you want to use this value. So they both only look at the name of the enum which is uppercased.
You can work around this by going through the documentations for XStream and/or Jackson and adding the right annotations.
Btw, you version of Cucumber is old. You may want to upgrade.

Related

Ensure a method is called from another?

I have a layer, call it Service and another called Permission. I was wondering if I could enforce a rule that says:
From within any public method of any public class within Service layer whose parameter list contains a parameter named foo, assert that it calls a method from Permission layer (and ideally, ensure it is called before anything else within the Service layer).
Is this possible with ArchUnit?
It does not work out of the box but you can achieve that goal with the following solution:
DescribedPredicate<JavaClass> isPermissionClass = JavaClass.Predicates
.resideInAnyPackage("..permission..");
classes()
.that().resideInAnyPackage("..service..")
.should(new ContainOnlyMethodsCallingPermissionClass(isPermissionClass));
ContainOnlyMethodsCallingPermissionClass can be defined as follows. It first collects all declared methods and then checks whether outgoing method calls to permission classes cover all collected methods.
public static class ContainOnlyMethodsCallingPermissionClass extends ArchCondition<JavaClass> {
private final DescribedPredicate<JavaClass> isPermissionClass;
public ContainOnlyMethodsCallingPermissionClass(DescribedPredicate<JavaClass> isPermissionClass) {
super("only contain methods calling a permission class");
this.isPermissionClass = isPermissionClass;
}
#Override
public void check(JavaClass javaClass, ConditionEvents events) {
Set<String> methodIdentifiers = getMethodIdentifiersOfClass(javaClass);
methodIdentifiers.removeAll(collectMethodsCallingPermissionClass(javaClass));
for (String methodId : methodIdentifiers) {
events.add(new SimpleConditionEvent(javaClass, false, methodId));
}
}
private Set<String> collectMethodsCallingPermissionClass(JavaClass javaClass) {
Set<String> methodIdentifiers = new HashSet<>();
for (JavaAccess<?> access : javaClass.getAccessesFromSelf()) {
if (!isCallFromMethod(access)) {
continue;
}
if (isMethodCallToPermissionClass(access)) {
JavaMethod callingMethod = (JavaMethod) access.getOwner();
methodIdentifiers.remove(callingMethod.getFullName());
}
}
return methodIdentifiers;
}
private Set<String> getMethodIdentifiersOfClass(JavaClass javaClass) {
return javaClass.getMethods().stream().filter(method -> !method.isConstructor())
.map(method -> method.getFullName()).collect(Collectors.toSet());
}
private boolean isCallFromMethod(JavaAccess<?> access) {
return access.getOrigin() instanceof JavaMethod;
}
private boolean isMethodCallToPermissionClass(JavaAccess<?> access) {
return isPermissionClass.apply(access.getTargetOwner());
}
}
You can also change the predicate operating on JavaClasses to one operating on JavaMethodCalls for locating relevant permission methods more precisely. This additionally allows filtering out irrelevant methods in the service layer (e.g., toString() methods).

Creating object in entity after all instance variables were set by Eclipse Link

The following JPA entity is given:
#Entity(name = "MyEntity")
public class MyEntity {
#Id
protected String id = null;
protected String name = null;
protected String adress = null;
#Transient
protected User user = new User(name, adress);
// Required by JPA
protected MyEntity() {
}
public MyEntity(String id, String name, String adress) {
// assign instance variables
}
public String getUser() {
return user.toString();
}
...
}
When getUser() will be called on MyEntity created by Eclipse Link the desired String will not be returned. The problem is that User was instantiated before the instance variables of MyEntity were set by Eclipse Link. In other words User was created with name = null and adress = null.
How can I ensure that User will be created after Eclipse Link has set all instance variables?
You can use the #PostLoad annotation like this:
#PostLoad
private initUser(){
user = new User(name, adress);
}
The method will be executed once your entity is fully loaded and it's fields are set.

Using Dapper.Net ORM, how do I cast stored procedure output to a concrete type?

Using Entity Framework I can create concrete classes from most of the sprocs in the database of a project I'm working on. However, some of the sprocs use dynamic SQL and as such no metadata is returned for the sproc.
So for a that sproc, I manually created a concrete class and now want to map the sproc output to this class and return a list of this type.
Using the following method I can get a collection of objects:
var results = connection.Query<object>("get_buddies",
new { RecsPerPage = 100,
RecCount = 0,
PageNumber = 0,
OrderBy = "LastestLogin",
ProfileID = profileID,
ASC = 1},
commandType: CommandType.StoredProcedure);
My concrete class contains
[DataContractAttribute(IsReference=true)]
[Serializable()]
public partial class LoggedInMember : ComplexObject
{
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Int16 RowID
{
get
{
return _RowID;
}
set
{
OnRowIDChanging(value);
ReportPropertyChanging("RowID");
_RowID = StructuralObject.SetValidValue(value);
ReportPropertyChanged("RowID");
OnRowIDChanged();
}
}
private global::System.Int16 _RowID;
partial void OnRowIDChanging(global::System.Int16 value);
partial void OnRowIDChanged();
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.String NickName
{
get
{
return _NickName;
}
set
{
OnNickNameChanging(value);
ReportPropertyChanging("NickName");
_NickName = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("NickName");
OnNickNameChanged();
}
}
private global::System.String _NickName;
partial void OnNickNameChanging(global::System.String value);
partial void OnNickNameChanged();
.
.
.
Without having to iterate through the results and add the output parameters to the LoggedInMember object, how do I map these on the fly so I can return a list of them through a WCF service?
If I try var results = connection.Query<LoggedInMember>("sq_mobile_get_buddies_v35", ... I get the following error:
System.Data.DataException: Error parsing column 0 (RowID=1 - Int64)
---> System.InvalidCastException: Specified cast is not valid. at Deserialize...
At a guess your SQL column is a bigint (i.e. Int64 a.k.a. long) but your .Net type has a n Int16 property.
You could play around with the conversion and ignore the stored procedure by doing something like:
var results = connection.Query<LoggedInMember>("select cast(9 as smallint) [RowID] ...");
Where you are just selecting the properties and types you want to return your object. (smallint is the SQL equivalent of Int16)
The solution to this was to create a complex object derived from the sproc with EF:
public ProfileDetailsByID_Result GetAllProfileDetailsByID(int profileID)
{
using (IDbConnection connection = OpenConnection("PrimaryDBConnectionString"))
{
try
{
var profile = connection.Query<ProfileDetailsByID_Result>("sproc_profile_get_by_id",
new { profileid = profileID },
commandType: CommandType.StoredProcedure).FirstOrDefault();
return profile;
}
catch (Exception ex)
{
ErrorLogging.Instance.Fatal(ex); // use singleton for logging
return null;
}
}
}
In this case, ProfileDetailsByID_Result is the object that I manually created using Entity Framework through the Complex Type creation process (right-click on the model diagram, select Add/Complex Type..., or use the Complex Types tree on the RHS).
A WORD OF CAUTION
Because this object's properties are derived from the sproc, EF has no way of knowing if a property is nullable. For any nullable property types, you must manually configure these by selecting the property and setting its it's Nullable property to true.

Get job title using System.DirectoryServices.AccountManagement

I've successfully used the AccountManagement code to retrieve basic AD information but it's only returning a very limited set of information about the returned object. How can I get extended information from AD using the AccountManagement functionality. Specifically the Job Title or title as it seems to be called in my instance of AD.
I know how to do it using the older DirectoryServices but I'd like to know how to do it using the new namespace.
Yes, the default set of properties on UserPrincipal is quite limited - but the great part is: there's a neat extensibility story in place!
You need to define a class descending from UserPrincipal and then you can very easily get access to a lot more properties, if needed.
The skeleton would look something like this:
namespace ADExtended
{
[DirectoryRdnPrefix("CN")]
[DirectoryObjectClass("User")]
public class UserPrincipalEx : UserPrincipal
{
// Inplement the constructor using the base class constructor.
public UserPrincipalEx(PrincipalContext context) : base(context)
{ }
// Implement the constructor with initialization parameters.
public UserPrincipalEx(PrincipalContext context,
string samAccountName,
string password,
bool enabled) : base(context, samAccountName, password, enabled)
{}
UserPrincipalExSearchFilter searchFilter;
new public UserPrincipalExSearchFilter AdvancedSearchFilter
{
get
{
if (null == searchFilter)
searchFilter = new UserPrincipalExSearchFilter(this);
return searchFilter;
}
}
// Create the "Title" property.
[DirectoryProperty("title")]
public string Title
{
get
{
if (ExtensionGet("title").Length != 1)
return string.Empty;
return (string)ExtensionGet("title")[0];
}
set { ExtensionSet("title", value); }
}
// Implement the overloaded search method FindByIdentity.
public static new UserPrincipalEx FindByIdentity(PrincipalContext context, string identityValue)
{
return (UserPrincipalEx)FindByIdentityWithType(context, typeof(UserPrincipalEx), identityValue);
}
// Implement the overloaded search method FindByIdentity.
public static new UserPrincipalEx FindByIdentity(PrincipalContext context, IdentityType identityType, string identityValue)
{
return (UserPrincipalEx)FindByIdentityWithType(context, typeof(UserPrincipalEx), identityType, identityValue);
}
}
}
And that's really almost all there is! The ExtensionGet and ExtensionSet methods allow you to "reach down" into the underlying directory entry and grab out all the attributes you might be interested in....
Now, in your code, use your new UserPrincipalEx class instead of UserPrincipal:
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// Search the directory for the new object.
UserPrincipalEx myUser = UserPrincipalEx.FindByIdentity(ctx, "someUserName");
if(myUser != null)
{
// get the title which is now available on your "myUser" object!
string title = myUser.Title;
}
}
Read all about the System.DirectoryServices.AccountManagement namespace and its extensibility story here:
Managing Directory Security Principals in the .NET Framework 3.5
Update: sorry - here's the UserPrincipalExSearchFilter class - missed that one in the original post. It just shows the ability to also extend the search filters, if need be:
public class UserPrincipalExSearchFilter : AdvancedFilters
{
public UserPrincipalExSearchFilter(Principal p) : base(p) { }
public void LogonCount(int value, MatchType mt)
{
this.AdvancedFilterSet("LogonCount", value, typeof(int), mt);
}
}
To Augment the above I have knocked up an extension method to call ExtensionGet. It uses reflection to get hold of the protected method you would otherwise have to inherit. You might need to use this if you are returning UserPrincipalObjects from Groups.Members, for example
public static class AccountManagmentExtensions
{
public static string ExtensionGet(this UserPrincipal up, string key)
{
string value = null;
MethodInfo mi = up.GetType()
.GetMethod("ExtensionGet", BindingFlags.NonPublic | BindingFlags.Instance);
Func<UserPrincipal, string, object[]> extensionGet = (k,v) =>
((object[])mi.Invoke(k, new object[] { v }));
if (extensionGet(up,key).Length > 0)
{
value = (string)extensionGet(up, key)[0];
}
return value;
}
}
There are simpler ways of getting to that info. Here is the way I got to Job Title in VB.NET:
Dim yourDomain As New PrincipalContext(ContextType.Domain, "yourcompany.local")
Dim user1 As UserPrincipal = UserPrincipal.FindByIdentity(yourDomain, principal.Identity.Name)
Dim Entry As DirectoryServices.DirectoryEntry = user1.GetUnderlyingObject()
Dim JobTitle As String = Entry.Properties.Item("Title").Value.ToString
To expand on Programmierus' comment, here is a simple way to do this on the fly in C#.
public static string GetProperty(UserPrincipal userPrincipal, string property)
{
DirectoryEntry d = (DirectoryEntry)userPrincipal.GetUnderlyingObject();
return d.Properties[property]?.Value?.ToString();
}

"Lambda Parameter not in scope" exception using SimpleRepository's Single method

I'm attempting to use the SimpleRepository to perform a fetch based on a non-ID property. Here's the Customer class I'm using:
[Serializable]
public class Customer : IEntity<Guid>
{
public Guid ProviderUserKey { get; set; }
public Guid ID
{
get; set;
}
}
I'm using SimpleRepository with migrations turned on. The code that throws the "Lambda Parameter not in scope" is below:
public class CustomerRepository :
ICustomerRepository
{
private readonly IRepository _impl;
public CustomerRepository(string connectionStringName)
{
_impl = new SimpleRepository(connectionStringName,
SimpleRepositoryOptions.RunMigrations);
}
public Customer GetCustomer(string userName)
{
var user = Membership.GetUser(userName);
// Code to guard against a missing user would go here
// This line throws the exception
var customer = _impl.Single<Customer>(c => c.ProviderUserKey.Equals(user.ProviderUserKey));
// Code to create a new customer based on the
// ASP.NET Membership user would go here
return customer;
}
}
I'm not sure at what point in the LINQ expression compilation this throws, but I am running this example on an empty database. The schema generations gets far enough to create the table structure, but can't evaluate the expression.
Does anyone know what I might be doing wrong?
Thanks!
I've had reports of this - can you add this (and your code) as an issue please?

Resources