PeopleSoft PSUnit

I first came across PSUnit in Jim Marion’s book PeopleSoft PeopleTools Tips & Techniques.  It’s a different tool from Test Framework – and you should consider it as complementary to PTF.

Jim has a write up of it here; there is another small explanation of it here.  Both articles give a link to the code, or you can get it here.

PSUnit is a Test Driven Development tool.  With Test Framework you code, create a page, and then put your page into a component.  The component gets applied to a menu which then get set into the registry.

With PSUnit you create a test framework Application Package, which gets plugged into an already existing test page.  Better yet – while Test Framework can help to point out where a transaction throws an exception, PSUnit lets you dig further and find out why.

From Jim Marion’s blog piece PSUnit Unit Testing Framework:

You, the developer, receive a notification from a user that page X of component COMP_X is calculating the wrong values. The user informs you that the calculation and error occur when he/she clicks save. From this information, you speculate that the calculation happens in the SavePreChange or SavePostChange event of the component or some record used in the component. Unfortunately, you are not familiar with this page or component.

With a PeopleCode trace, you are able to identify six potential events. You notice that these events call FUNCLIB’s and App Classes creating a horrendously deep call stack. From what you have in front of you, it is obvious that a quick review of this 3,000+ line trace file won’t provide an easy solution.

At this point you have several options:

Continue to treat COMP_X as a black box, investigating it from the outside.

Dig into the code and speculate as to its purpose.

Configure app server debugging and step through the deep call stack.

Start adding MessageBox statements to the delivered code so you can interrogate the state of the application as it runs.

We will choose the final option, the MessageBox option. Yes, this will require us to modify delivered code, but this modification should have no impact on the behavior of the code. The modification doesn’t concern me as much as forgetting to delete one of those MessageBox statements after I find and fix the problem. And then, once I find the correct combination of MessageBox statements to show the problematic data or logic, I hate to delete them, knowing I may have to visit this code at a future date (sooner then I want, but far enough in the future that I’ve already forgotten how I solved the problem). Wouldn’t it be nice if, once you found the appropriate combination of logging statements, you could just leave them in the code?

You should read the entire post.  I’ll list the various Assert tests that are available in another post.

Advertisements

More fun with Application Packages – Instances

In my last post I had made this statement:

Instance variables are like Static variables in Java.

Hat tip to Helena who provided insight:

One comment though – instance variables are not static variables (in terms of scoping rules, one the same private instance variable is not shared by multiple instances of the class); they are in fact instantiated for each instance/object of the class.

So if I have a class definition ClassDef, with 1 private instance variable &InstanceVar, and I instantiate 2 objects of type ClassDef, I will have 2 instances of &InstanceVar in memory, not just 1.

This contrasts with static member variables in Java, where the variable is shared and in the example above, only 1 instance of &InstanceVar would have been allocated in memory.

Good point – so lets dig into this a bit – as others have here and here.

Since I made the statement like Static variables in Java let’s look at what those are.  From Oracle’s Java Tutorials on Understanding Instance and Class Members:

When a number of objects are created from the same class blueprint, they each have their own distinct copies of instance variables. In the case of the Bicycle class, the instance variables are cadence, gear, and speed. Each Bicycle object has its own values for these variables, stored in different memory locations.

Sometimes, you want to have variables that are common to all objects. This is accomplished with the static modifier. Fields that have the static modifier in their declaration are called static fields or class variables. They are associated with the class, rather than with any object. Every instance of the class shares a class variable, which is in one fixed location in memory. Any object can change the value of a class variable, but class variables can also be manipulated without creating an instance of the class.

I added the bolding and underlining in the above.  So as Helena pointed out, in Java the same memory location is used by every instance of the class having a variable defined as static.  Each instance of a class gets a reference (having been weaned with C I would say pointer but a Java purist would start throwing acorns at me) to the location in memory where the value actually resides.  Which falls in line with how memory allocation works in Java.  Java stores objects on the heap, variables sit on the stack.  But variables are ‘merely’ pointers/references to the objects sitting on the stack.  Enough teasing – I also know there are differences between a pointer and a reference – but that is a C++ convention, not C.  In any event, it’s efficient for Java to have Static variables work this way.

PeopleBooks provides this tidbit in Declaring Private Instance Variables:

A private instance variable is private to the class, not just to the object instance. For example, consider a linked-list class where one instance needs to update the pointer in another instance. Another example is the following class declaration:

class Example private instance number &Num; end-class;

A method of Example could reference another instance of the Example &Num instance variable as:

&X = &SomeOtherExample.Num;

Avoid making every instance-scoped variable a public property. You should consider each variable individually and decide if it belongs in the public interface or not. If it does, decide if the variable warrants get or set modifiers and therefore should be a public property. If the variable only serves internal purposes to the class, it should be declared as a private instance variable.

Again, I added bolding and underline.  But note the word pointer – a double plus unJava word.  So lets look at a language that does use pointers.

I’m a pack rat.  I don’t throw books away.  So I looked in my collection and grabbed my copy of Deitel & Deitel C++ How To Program:

Each object of a class has its own copy of all the data members in the class.  In certain cases only one copy of a variable should be shared by all objects of a class…  A static class variable represents “class-wide” information. 

Let us motivate the need for static class-wide data with a video game example.  Suppose we have a video game with Martians and other space creatures.  Each Martian needs to be brave and willing to attack other space creatures when the Martian is aware that there are at least 5 Martians present.  If there are fewer than 5 Martians present, each Martian becomes cowardly.  So each Martian needs to know the martianCount.  We could endow class Martian with martianCount as a data member.  If we do this, then every Martian will have a separate copy of the data member and every time we create a new Martian we will have to update the data member martianCount in every Martian.  This wastes space with the redundant copies and wastes time in updating the separate copies.  Instead, we declare martianCount to be static.  This makes martianCount class-wide data.  Every Martian can see the martianCount as if it were a data member of the Martian, but only one copy of the static martianCount is maintained by C++  This saves space.  We save time by having the Martian constructor increment the static martianCount.  Because there is only one copy, we do not have to increment separate copies of martianCount for each Martian object.

Hmmm.  Something fishy here.  Both C++ and Java are using static variables the same way.  Let’s look at PeopleSoft some more.  There is some code here that bolsters what Helena had pointed out.  The instance in an App Package class gets instantiated as its own distinct block of memory – so it breaks the notion and value of having a C++/Java type static variable.  However it’s able to be referenced and changed by another instance of the same class.   So take the less efficient part of the Deitel explanation and there you have it.

To my mind this is bordering on an architectural bad smell of connector-envy, and can lead to some code smells on the part of development.

Defining and Using Constants with PS Application Package

I’ve used Application Packages more and more after reading about them in Jim Marion’s PeopleSoft PeopleTools Tips & Techniques.  And I like using them far more than creating functions in a FUNCLIB_ library.

I’ve got an App Engine program I’m developing, and I’m using an App Package class for error handling.  I’ve a small list of error codes that get sent by the exception handler routine and those codes are used to get a description.  I could use message catalog for the texts of course, but in this case I’m going to be lazy and keep the values in the code.  This is for a batch process that will be scheduled to run nightly; it isn’t customer facing.

To avoid having magic numbers appear in my code I wanted to define a set of constant integer values in the App Package class.  PeopleBooks gets a bit obtuse on this subject though.

So, let’s go thru the exercise of creating them, then how to use them.

In the class definition I create a private constant:

private
Constant &INVALID_EMPLID = 1;

So far, so good.  any methods inside the class can use that value:

Evaluate &errCode
When = &INVALID_EMPLID
&msg = “Invalid emplid provided.”;
Break;

But I want the code throwing the exception access to the same constant.  PS App Package definitions are – well – eccentric.

Java, C++ and C# class structures look similar.  You define the class, then add fields if needed, and the methods of the class.

App Packages have methods, but then bring in the idea of properties and instances as well as Constants.

A property is exactly that, it’s a property of the instantiated object from the class – it’s the Has A of the object.  As in my class House Has A property of RoomColor.  PeopleBooks provides an explanation for a property as an attribute of an object.

Instance variables are like Static variables in Java.  An instance is private to the class, not just to the instantiated object.

Which gets us nowhere in terms of having our constant value used in my exception handling – yet.

Here is the key part – PeopleSoft set up properties to take the place of creating get and set methods.  They consider it more efficient to declare a property (which has no parameters) than to use a method to do get/set routines.

So instead of having a method:

method getSomething() as integer;

You would instead declare a property:

property integer mySomething get;

This was the long way around to explain how I get to use my Constants definition.  You saw above where I created a constant for &INVALID_EMPLID.

I declare a public (this has to be public – PS will bark at you if you try to do anything else with it) property – making sure it has a get as part of the definition:

property integer invalidEmplid get;

Then you write a get routine:

get invalidEmplid
/+ Returns Integer +/
Return &INVALID_EMPLID;
end-get;

Now my App Engine code can access that constant value – assuming that I’ve declared the App Package Class inside the code:

&errnum = &err.invalidEmplid;

If I find later on that I want to change the value &INVALID_EMPLID points to, I only have to do it in one place.  Less code maintenance, which is the real value of not using magic number coding.

Extending PeopleSoft FTPClient App Package Class

This post will be covering a few items under the same topic.

We ran into problems with the built in FTP PeopleCode functions with 8.51.  So for example, to use GetAttachment, one of the parameters you are to supply is URLDestination, which would resolve to something like:

ftp://anonymous:hobbit1@ftp.ps.com

Where anonymous is the user name, and hobbit1 the password.

If you are in an Active Directory situation, and the domain needs to be a part of the username:

<domain name>/<user name>

With tools 8.51 that slash throws an error.  So to resolve this we stopped using the built-in functions, replaced them with calls to the supplied HCSC:FTP:CLIENT:FTPClient Application Package/Class.

The class FTPClient calls an open source netcomponents.jar file, provided by www.savarese.org.

There is a problem with the delivered app package however, the developers never allowed for the FTP return codes.  I’m providing a simple fix. While I was at it, I added FTP rename and delete functionality.

I created an App Package, then added a new class with the methods I wanted:

class FTPClientExtended extends HCSC:FTP:CLIENT:FTPClient
/** Constructor*/
method FTPClientExtended();
/*
Returns the integer value of the reply code of the last FTP reply.
You will usually only use this method after you connect to the FTP
server to check that the connection was successful since connect is of type void.
*/
method getReplyCode() Returns integer;

/*
Returns the entire text of the last FTP server response exactly as it was received,
including all end of line markers in NETASCII format.
*/
method getReplyString() Returns string;

/*
Renames a remote file.
Parameters:from – the name of the remote file to rename.
to   – the new name of the remote file.
Returns:True if successfully completed, false if not.
*/
method rename(&from As string, &to As string) Returns boolean;

/* Deletes a file on the FTP server.
Parameters:pathname – The pathname of the file to be deleted.
Returns:True if successfully completed, false if not. */
method deleteFile(&pathName As string) Returns boolean;

protected

/** holds reference to Java ftp object */
property JavaObject _ftp;

end-class;

Note the extended keyword.  This class is now a subclass of the delivered FTPClient.

The constructor does the heavy lifting for us:

/**
Constructor
*/
method FTPClientExtended

/* Create the base class constructor */
%Super = create HCSC:FTP:CLIENT:FTPClient();

/* create pointer to Base class Java object */
&_ftp = %Super._ftp;

end-method;

We create Superclass references to the class and the base class Java object.   Take a look at the delivered FTPClient Application Class constructor:

method FTPClient

/* Create the base class constructor */
%Super = create HCSC:COMMON:BASE:JavaBase(“com.peoplesoft.hr.hr.ftpclient.ExFTPClient”);

/* create Java object for splitter */
&_ftp = %Super.getJavaObject();

end-method;

The base class FTPClient is iteslf using Superclass references.

The rest gets very straight foward:

method getReplyCode

/+ Returns Integer +/

/* Return the FTP code – use to determine if failed or successful */

Return &_ftp.getReplyCode();

end-method;

method getReplyString

/+ Returns String +/

/* Returns the entire text of the last FTP server response exactly as it  was received, including all end of line markers in NETASCII format.  */

Return &_ftp.getReplyString();

end-method;

method rename

/+ &from as String, +/

/+ &to as String +/

/+ Returns Boolean +/

Return &_ftp.rename(&from, &to);

end-method;

method deleteFile

/+ &pathName as String +/

/+ Returns Boolean +/

Return &_ftp.deleteFile(&pathName);

end-method;

By creating a new Package and class, I’ve added functionality but without having to customize the delivered code.  Come upgrade time this is (hopefully!) going to be a lot easier to deal with.

Beware the widget

The Jabberwock, as illustrated by John Tenniel

 “Beware the Jabberwock, my son!

The jaws that bite, the claws that catch!

 Beware the Jubjub bird, and shun The frumious Bandersnatch!”

 So, I wanted a simple drop down list so a tester/player could pick a scene and then go there.  I didn’t find what I wanted, but there was this nice feature of the Corona Widget object library called the newTableView:

 Corona tableView widget

Looks good, maybe more complicated than what I need but the code looks straight forward (okay, not as easy and straight forward as old school classic VB 6 – but not as weird and hard as Visual C++ MFC of the same era – and once again I’m dating myself…)

The demo’s I found here and here provided the basics – but!  I need to incorporate this inside the Corona Storyboard construct.  And that is where the fun and games began…

Now a mea maxima culpa is in order – what follows is probably due to my being overzealous in getting rid of memory issues.

I created two arrays – one is a straight forward array with the names of the scenes in order that I want to provide.

The second is an array of arrays used by the tableView object.  One of the weaknesses in using Corona is the documentation is sparse and terse – just enough to get you into trouble – but the stuff you really need to know is found in the forums. From what I’ve figured out is the row construct in the list allows you to have a picture object, a title and then descriptive text. There may be more, but this is far more at this point than what I really need.  Hence an array of arrays – or to use the Lua way of thinking – a table with individual rows that could contain a number of fields (columns) greater than one.  Let’s move on.

 He took his vorpal sword in hand:

Long time the manxome foe he sought—

So rested he by the Tumtum tree,

And stood awhile in thought.

 Got my lists, got my tableView, and wow – it actually displays what I want!

It’s just that the damn thing crashes when I do a selection.  This one got me.

And as in uffish thought he stood,

The Jabberwock, with eyes of flame,

Came whiffling through the tulgey wood,

And burbled as it came!

So I unsheathed my vorpal sword – er, I started to really use the Lua Glider debugger.  Need to go back a bit here.  In my desire not to create any more memory leaks I had made sure in the storyboard function scene:exitScene I set any variable I declared to nil.  And that was the source of my errors.

One, two! One, two! and through and through

The vorpal blade went snicker-snack!

He left it dead, and with its head He went galumphing back.

The errors were just – weird.  Didn’t make sense.  And here is where using Lua Glider saved the day (used as my vorpal blade).  I set a break point for the listener function in my code – the code that gets fired when a user clicks on a selection in the list.

And as I expected the code worked perfectly – selecting the correct item in the selection array based off the event index.  But then we went down the rabbit hole…

It turns out after all of that the storyboard code kicked in.  The exitScene code got called – setting all of my variable to nil.  Oh – and then the listener function got called again – and since everything had just been set to nil it set off errors – oh my…

Okay, I’m sure my code isn’t the most efficient at this point.  Why the listener function is getting called twice I can’t answer.  However I did learn a valuable lesson here.

“And hast thou slain the Jabberwock?

Come to my arms, my beamish boy!

O frabjous day! Callooh! Callay!” He chortled in his joy.

 ‘Twas brillig, and the slithy toves

Did gyre and gimble in the wabe;

All mimsy were the borogoves,

And the mome raths outgrabe.

Clearly, at this point in my Lua/Corona development the ONLY stuff I should be setting to nil (null) in the storyboard scene:exitScene function are those objects that get inserted into the display view/self view group.  Anything else – well as the maps used to say here be dragons

Cross posted at my other blog SE Studio Team C

Been busy at my other Blog site

I noticed I haven’t posted at this site in a while, I’ve been busy with several projects and writing at another blog site.

Since last September I’ve been working with a small team creating a cross-platform game using Corona SDK.  We’ve called our project Flights of Fancy, and we’re doing weekly write ups here.

Corona SDK uses Lua as the scripting language – I find it very much like classic VB.  Easy to get into which means you can write a lot of bad code – but capable of doing some elegant programming.

One interesting aspect of our group – we’ve never met in person.  And we are spread out across the US; one of us on the east coast, one on the west coast and the rest spread in the mid-west.  We use Skype, Google products, Trello and Mantis BT to keep everything on track.

2012 in review – Thanks to All!!

The WordPress.com stats helper monkeys prepared a 2012 annual report for this blog.

Here’s an excerpt:

600 people reached the top of Mt. Everest in 2012. This blog got about 3,400 views in 2012. If every person who reached the top of Mt. Everest viewed this blog, it would have taken 6 years to get that many views.

Click here to see the complete report.

PeopleSoft Test Framework and IE9 issues

We ran into problems with PTF in that tests we had created earlier this year wouldn’t work.  Worse, the errors were inconsistent – first it would refuse to enter the current login information; it would throw errors after opening up the browser; PTF would just hang when at a search screen and wait instead of entering information from the script.  Our company had done an upgrade to IE9 from IE 8 a few months back; it looked once again as if IE9 was the culprit.

Our tools level is 8.51.1.  Doing a web search returned some hits – mostly of the ‘IE9 is not compatible with PTF’ variety.  So yes that sort of validated our hunch, but didn’t really supply a direction to go.

Searching in the Oracle Knowledge Base was frankly a waste of time.  Then we started looking into PeopleTools patches – and found there have been patches to PTF since our release.  In point of fact the patch for 8.51.14 had this bug mentioned as fixed – 12912401 PTF – Synch Issues with IE9.

We looked up the bug and found the text of the reported bug:

Hdr: 12912401 N/A TFRM 8.51 PRODID-5085 PORTID-289
Abstract: PTF – SYNC ISSUES WITH IE9  
*** 08/24/11 08:25 am *** 
Can not recognize innerText=QAS_TST_MSGSETS in IE9(PTF 852 902R1) 
 PTF throw error in log as object not found or access denied when executing in IE9.  The same test ran successfully in IE8
 
1.Execute process_run at IE9 and got unstable issue(each time got different issue)
2.Uninstall IE9 and reinstall IE8
3.Reexecute process_run at IE8 the script executed fine

Not wanting to do a complete PeopleTools patch to the system we tried the following:

  • Uninstalled PTF from the client machine.
  • Downloaded the 8.51.20 patch, and ran the setup in a client PC.
  • Navigated to the newly created PT8.51.20\setup\PSTestFramework folder.
  • Ran the setup.exe program.

That’s all it took.  The patched 8.51.20 version of PTF works with IE9; the few tests we had created with the earlier version using IE8 now run to success.

The PTF Signon screen displays PeopleTools 8.51.20, but it works fine with our current 8.51.10 Integration Broker setup and Oracle database.

PeopleSoft Integration Broker setup for Test Framework – Part V

How to get to the Integration Broker Error Log.

In our environment we use Windows as our web server OS.  So the paths I’m giving here may not be correct for a UNIX flavor environment.

In any event, to reach this log you need to have read access to the webserv directory on your web server.  The path should be something like:

<instance name>\webserv\<instance name>\applications\peoplesoft\PSIGW.war\errorLog.html

This log provides information in this general format:

  • Time and Date of error
  • Error Type
  • Error Level
  • Description of error
  • Message Catalog Information
  • Stack Trace
  • Request
  • Response

The Message Catalog information is from PeopleTools – and it points you in the general direction.  There may or may not be MessageParms which can further help with debugging.

Next, this is a Java web/servlet application.  So the stack trace is a Java exception log.  Sort of useful to read and get a handle on what is going on, but the other two panels may help more.

The Request part shows the SOAP XML request sent by PTF  to the Anonymous Node.  The listener for Integration Broker gets this HTTP request and attempts to route it to the correct node.

The Response part shows the SOAP XML message being returned by the listener.

So what is the usefulness of this?  Well – PTF is kinda dumb, but maybe in a smart way.  If it can’t make a connection to a node it makes you think you put in the wrong user name or password.  Good for a web login for security purposes – but come on!  This tool isn’t for the general user.

So the IB log can tell you things that the PTF login won’t.  I find it useful as I step thru the process of making changes in Integration Broker, attempt to log in, then look at the error log file.  As changes are made you should see different errors thrown until you get to that magic moment where PTF has logged into the node and the tool IDE opens up.

PeopleSoft Integration Broker setup for Test Framework – Part IV

Let’s cover security that is needed to use PTF in terms of Integration Broker.

First of all, the Default User ID of your Anonymous Node.  Let’s cover the roles that user ID should have:

  • PeopleTools
  • PTF Administrator

I’ve also added PTF Editor, PTF User to the node user ID.

Couple of other things – these are settings that should be set by default in your Service Operations.

  • Service Operation GENCOMPONENTURL_SO should have permissions PTPT1000 (PeopleSoft User) and PTPT3400 (PTF Admin).
  • Service Operation PTTST_CONFIG should have permissions PTPT3400 (PTF Admin), PTPT3600 (PTF Editor) and PTPT3700 (PTF User) assigned. All three permission lists should have Full Access.
  • Service Operation PT_SOAPTESTER should have permissions PTPT1000 (PS User) and PTPT 3400 (PTF Admin); again these permissions should have Full Access set.  I usually add permissions ALLPANLS but your mileage may vary.

Your users are also going to have to have one of the thee PTF roles assigned, as well as PeopleTools.

We are winding down here, next post should cover it.  There I’m going to cover an IB error log that can be very useful.

%d bloggers like this: