Project

General

Profile

Bug #8353

Fully support stanza INI LOAD/USE/UNLOAD scenarios

Added by Roger Borrello over 2 years ago. Updated over 1 year ago.

Status:
WIP
Priority:
Normal
Assignee:
-
Target version:
-
Start date:
Due date:
% Done:

0%

billable:
No
vendor_id:
GCD
case_num:
version_reported:
version_resolved:
reviewer:
production:
No
env_name:
topics:

Related issues

Related to User Interface - Feature #4517: optionally back the 4GL features for Registry access with the user-specific offline storage features Closed

History

#1 Updated by Roger Borrello over 2 years ago

  • Related to Feature #4517: optionally back the 4GL features for Registry access with the user-specific offline storage features added

#2 Updated by Roger Borrello over 2 years ago

Continuing progress on #4517...

When I introduced a testcase, there is other breakage since there are strange aspects to how Progress deals with LOAD/USE/UNLOAD in the areas of:
  • The .ini extension doesn't seem to be required, it is added when needed
  • The case of the INI value must match between LOAD/USE/UNLOAD.

The testing setup is taking longer than the code update, but I believe my updates in revision 15010 of this branch now handle what I've been able to test much better.

The rules I've found via checks on Progress are:
  • The fname and envname are 2 distinct entities in LOAD/USE/UNLOAD
  • In LOAD, envname is the fname stripped and fname is forced to .ini extension, if none given.
    • fname is the primary key. Lookups are done matching the envname to the filename and the first match is returned.
  • In USE/UNLOAD, if an extension is passed it must match the fname, or fail.
    • If an extension is not passed, first envname is checked for. If not found, then .ini appended and checked against the fname.
  • All checks are case-sensitive
I am trying to form tests that work in the new methodology, but so far I haven't had luck. Mostly because of my lack of 4GL skills. The testcase should:
  1. use various combinations of names passed to LOAD and attempt USE/UNLOAD with matching/non-matching combinations.
  2. utilize multiple LOAD statements in various orders, and verify using GET-KEY-VALUE to validate values.
  3. determine if a new file is created properly by writing/reading
  4. read groups of sections and keys by passing null where appropriate
  5. be performed in GUI and ChUI

There is a bug in the reading of a file when a section is the last line:

[section1]
key1 = value3txt1
key2 = value3txt2
[section2]

I have to add a newline at the end of the file for section2 to be found.

Here is my currently manual testcase:

def var path as char init "testcases_v2/abl/stanza_ini".
def var inidir as char.
inidir = "z:/" + path.
if opsys = "unix" then
   inidir= "/home/rfb/" + path.
if opsys <> "win32" then
   message opsys "is an unsupported OS".

DEFINE VARIABLE keyval AS CHARACTER NO-UNDO FORMAT "x(128)".

/* Normal checks */
load "env.1.inifile" dir inidir base-key "INI".
use "env.1.inifile".
GET-KEY-VALUE SECTION "section1" KEY "key1" VALUE keyval.
message "keyval="keyval.
use "".
unload "env.1.inifile".

load "env1.ini" dir inidir base-key "INI".
use "env1".
GET-KEY-VALUE SECTION "section1" KEY "key1" VALUE keyval.
message "keyval="keyval.
use "".
unload "env1".

load "env1" dir inidir base-key "INI".
use "env1.ini".
GET-KEY-VALUE SECTION "section1" KEY "key1" VALUE keyval.
message "keyval="keyval.
use "".
unload "env1".

load "env1.ini" dir inidir base-key "INI".
use "env1.ini".
GET-KEY-VALUE SECTION "section1" KEY "key1" VALUE keyval.
message "keyval="keyval.
use "".
unload "env1.ini".

load "env3.txt" dir inidir base-key "INI".
load "env3" dir inidir base-key "INI".
use "env3".
GET-KEY-VALUE SECTION "section1" KEY "key1" VALUE keyval.
message "keyval="keyval.

GET-KEY-VALUE SECTION "" KEY "key1" VALUE keyval.
message "keyval="keyval.

GET-KEY-VALUE SECTION "section1" KEY "" VALUE keyval.
message "keyval="keyval.

GET-KEY-VALUE SECTION "section" KEY DEFAULT VALUE keyval.
message "keyval="keyval.
unload "env3".

use "".
GET-KEY-VALUE SECTION "section1" KEY "key1" VALUE keyval.
message "keyval="keyval.

#3 Updated by Roger Borrello over 2 years ago

I was able to learn enough to be dangerous for creating an ABL Unit testcase for stanza_ini. These 2 files are in tests/stanza_ini.

Suite.cls:

block-level on error undo, throw.

@TestSuite(classes="tests.stanza_ini.Test").
class tests.stanza_ini.Suite:
end class.

/* EOF */

Test.cls:

using OpenEdge.Core.Assert.

block-level on error undo, throw.

/* Core tests for stanza INI file usage, refs #8353 */

class tests.stanza_ini.Test:

   @Before.
   method public void UT_SceneSetup():
      session:suppress-warnings = false.
   end method.

   @After.
   method public void UT_SceneTeardown():
   end method.

   @Setup.
   method public void UT_TestSetup():
      os-delete ./env.ini.
   end method.

   @TearDown.
   method public void UT_TestTeardown():
      os-delete ./env.ini.
   end method.

   @Test.
   method public void TestSimpleNoIni():
      /* Case 1 load should fail. No oddities */
      LOAD "env.ini" DIR "./".
      support.test.AssertExt:Error(4449, 'The LOAD of env.ini in path ./ failed. (4449)').
   end method.

end class. /* Test */

/* EOF */

But there is a failure in conversion:

     [java] ------------------------------------------------------------------------------
     [java] Code Conversion Annotations
     [java] ------------------------------------------------------------------------------
     [java] 
     [java] Optional rule set [customer_specific_annotations_prep] not found.
     [java] ./tests/stanza_ini/Suite.cls
     [java] ./tests/stanza_ini/Test.cls
     [java] Null annotation (full-java-class) for support.test.AssertExt [CLASS_NAME] @32:7 (231928234154)
     [java] Null annotation (simple-java-class) for support.test.AssertExt [CLASS_NAME] @32:7 (231928234154)
     [java] Null annotation (containing-package) for support.test.AssertExt [CLASS_NAME] @32:7 (231928234154)
     [java] Null annotation (found-in-full-java-class) for Error [OO_METH_VOID] @32:30 (231928234155)
     [java] EXPRESSION EXECUTION ERROR:
     [java] ---------------------------
     [java] persist()
     [java] ^  { null value for annotation 'full-java-class':support.test.AssertExt [CLASS_NAME]:231928234154 @32:7
     [java]  }
     [java] ---------------------------
     [java] ERROR:
     [java] com.goldencode.p2j.pattern.TreeWalkException: ERROR!  Active Rule:
     [java] -----------------------
     [java]       RULE REPORT      
     [java] -----------------------
     [java] Rule Type :   POST
     [java] Source AST:  [ block ] BLOCK/ @0:0 {231928233985}
     [java] Copy AST  :  [ block ] BLOCK/ @0:0 {231928233985}
     [java] Condition :  persist()
     [java] Loop      :  false
     [java] --- END RULE REPORT ---

I'm not too familiar with OO conversion. Is there any pointers to what this might be?

#4 Updated by Roger Borrello over 2 years ago

The failure was because I didn't include support/test/AssertExt.cls in the conversion file. Now I get:

    [javac] /home/rfb/projects/testcases_v2_dev2/src/com/goldencode/testcases/tests/stanza_ini/Suite.java:14: error: incompatible types: Suite cannot be converted to Annotation
    [javac] @Suite
    [javac]  ^
    [javac] /home/rfb/projects/testcases_v2_dev2/src/com/goldencode/testcases/tests/stanza_ini/Test.java:80: error: incompatible types: Test cannot be converted to Annotation
    [javac]    @Test(order = 1)
    [javac]     ^
    [javac] 2 errors

The Suite.java was created, so I'm not sure what I did wrong. Vladimir, if there's any help getting this "Hello World" testcase going, I'd appreciate it.

...
/**
 * Business logic (converted to Java from the 4GL source code
 * in tests/stanza_ini/Suite.cls).
 */
@Suite
@SelectClasses(value = 
{
   "tests.stanza_ini.Test" 
})
public class Suite
extends BaseObject
{
...

#5 Updated by Roger Borrello over 2 years ago

  • Assignee set to Roger Borrello
  • Status changed from New to WIP

By changing my test to a procedure, I was able to get it running.

I am finding that LOAD gIniName DIR gDir. results in NPE when we get to the client side EnvironmentDaemon.load, as baseKey is null:

   public boolean load(String env,
                       String directory,
                       boolean flagNew,
                       String baseKey)
   {
      EnvironmentReader envAcc;
      Map<String, EnvironmentReader> envs;

      boolean isIniType = EnvironmentReader.TYPE_INI.equalsIgnoreCase(baseKey);
      if (!isIniType && !PlatformHelper.isUnderWindowsFamily())
      {
         envs = envFallbackMap;
         env = env.toLowerCase();
         envAcc = new FallbackEnvironmentReader(env, clientStorage, baseKey.toLowerCase());   // <-- NPE here
      }

I'm thinking we should invoke from the server side EnvironmentOps.load with more protection:
      if (baseKey != null)
      {
         baseKeyAsString = baseKey.toStringMessage();
      }
      else  // Add an else case
      {
         baseKeyAsString = new String("");
      }

      if (!Environments.load(envAsString, directoryAsString, flagNewAsBoolean, baseKeyAsString))
      {
         onLoadError(env, directory);
      }

#6 Updated by Roger Borrello over 2 years ago

Actually, the fact that baseKey is null should be OK on the client side. It just needs to be a little more protected, since FallbackEnvironmentReader can accept a null:

      boolean isIniType = EnvironmentReader.TYPE_INI.equalsIgnoreCase(baseKey);
      if (!isIniType && !PlatformHelper.isUnderWindowsFamily())
      {
         envs = envFallbackMap;
         env = env.toLowerCase();
         baseKey = (baseKey != null) ? baseKey.toLowerCase() : baseKey;
         envAcc = new FallbackEnvironmentReader(env, clientStorage, baseKey);
      }

There is a problem with this case of trying to load a file that doesn't exist, such as my first testcase, LOAD "env.ini" DIR "./". because we get to the fallback environment. In Progress, we get an error, because somehow it knows that env.ini is a file, even though it doesn't exist, and we don't specify basekey "INI".

The LOAD documentation for environment has:

A CHARACTER expression that evaluates to one of the following:
  • The name of a registry key to create
  • The name of an initialization file to create
  • The name of an existing registry key
  • The name of an existing initialization file

So I am not sure how to get boolean isIniType to be true, if we don't have a file, nor pass the basekey. Perhaps assuming it is INI if there is .ini at the end of the environment?

#7 Updated by Greg Shah over 2 years ago

Actually, the fact that baseKey is null should be OK on the client side. It just needs to be a little more protected, since FallbackEnvironmentReader can accept a null:

Correct, the null has meaning.

Perhaps assuming it is INI if there is .ini at the end of the environment?

It seems reasonable approach if basekey is null or possibly if it is the empty string (please check this in the 4GL).

#8 Updated by Roger Borrello almost 2 years ago

I did a test on the legacy application, and that was to remove the .ini that is loaded upon executing the "Edit colors" function. In FWD, we exit the application, since the error condition is passed on. When I debugged, the legacy application didn't display any error regarding the file not being found, like we do in FWD. Just an observation that needs to check out the NO ERROR results in a testcase.

#9 Updated by Roger Borrello almost 2 years ago

I am trying to duplicate the situation on the customer application where the INI file is not found when a USE occurs. However, this is a Windows GUI and the server is Unix. In Progress, does this Windows client still look in the Windows OS for the INI file? It doesn't look at the server, correct?

#10 Updated by Galya B almost 2 years ago

OE doc on LOAD says in Notes (the last section) what's the exact order of looking for the environment. When BASE-KEY "INI" is not added, Progress looks through the registry with and without the extension of the environment name and finally checks for the file. In the whole process ".ini" is never added to the file name. Initialization files in Progress can have any extension. The only ".ini" coming from Progress is when NEW BASE-KEY "INI" needs to create a new file and .ini is added to the env name. The environment having or not having .ini in the name seems irrelevant to any lookup logic, so env.ini is a valid registry env and inifile is a valid initialization file. So this .ini concat in our code seems wrong.

The other thing: EnvironmentDaemon.load should be extended to do an actual search in the registry before assigning envAcc, when the OS is Windows, baseKey is not "ini" and flagNew is false. Then if not found, set the env as ini continue with the current load logic.

It can get messy with such rework, so posting the results of the tests in both Progress and FWD can help pinpoint the necessary changes.

As for the server / client question. Isn't Progress running thick desktop clients, so they are always on the 'server'?

#11 Updated by Galya B almost 2 years ago

One more thing, since one and the same env name can be both a registry entry and an ini file in different calls, we still need to account for it. With all environments going in the same map, something needs to change.

#12 Updated by Greg Shah almost 2 years ago

In Progress, does this Windows client still look in the Windows OS for the INI file?

Whether it is a registry lookup or an INI file access, the LOAD statement is exclusively executed on the local OS.

It doesn't look at the server, correct?

Correct.

Isn't Progress running thick desktop clients, so they are always on the 'server'?

Yes, they are thick desktop clients. They do not call over to the appserver to do the LOAD which I think is what Roger was asking about.

#13 Updated by Roger Borrello almost 2 years ago

Greg Shah wrote:

Yes, they are thick desktop clients. They do not call over to the appserver to do the LOAD which I think is what Roger was asking about.

Exactly. I was trying to duplicate the scenario on the customer's configuration, and it worked whether the file.ini existed or not. I wasn't sure if renaming it on the client workstation should have been enough.

I know I'm focusing a lot on this particular customer's configuration, but I'm trying to get my head around how Progress handles INI files. I don't even see where the application is performing a LOAD, since my break point in EnvironmentalDaemon.load() was never hit. I was under the impressiona LOAD has to be performed first, and my simple testcase bears that out. It's difficult to plan a testcase if Progress behaves differently under different configurations, like a thick desktop client versus a Windows VM running prowin.exe.

#14 Updated by Greg Shah almost 2 years ago

In that customer's case, aren't they specifying the -ininame command line parameter in OE? In other words, it is a kind of implicit LOAD statement.

#15 Updated by Roger Borrello almost 2 years ago

Greg Shah wrote:

In that customer's case, aren't they specifying the -ininame command line parameter in OE? In other words, it is a kind of implicit LOAD statement.

I believe so, but the INI specified on the command line isn't the same as the one specified in the USE statement.

#16 Updated by Greg Shah almost 2 years ago

And what is the USE statement? If it is USE "". then it is just making the default environment the current environment.

#17 Updated by Roger Borrello almost 2 years ago

Greg Shah wrote:

And what is the USE statement? If it is USE "". then it is just making the default environment the current environment.

No, it's USE inifile without an extension. When the system is available, I'll take another look and note specifics.

#18 Updated by Roger Borrello almost 2 years ago

The command line used is: C:\Progress\OpenEdge\bin\prowin32.exe -assemblies clientnet -basekey "ini" -ininame progress-medium -pf xxx.pf
The directory is: C:\DEV\sources\client

The progress-medium.ini file is found in C:\Users\fwd\Desktop\backup\client which is also where the appname-DEV-HV01.ini is found that the USE is "using". But like I said, I can't seem to catch any LOAD when I debug the FWD application by breaking in FWD. If there is a place where LOAD is performed, it might help to get the customer to point it out, since I don't think -ininame is doing it. There's no mention of the appname-DEV-HV01.ini in the progress-medium.ini file.

#19 Updated by Galya B almost 2 years ago

Is initialization-file (progress-medium) specified in the client bootstrap configs for the FWD client? It is supposed to call EnvironmentDaemon.setDefaultEnvironment and set defaultEnv instead of calling load.

As for appname-DEV-HV01.ini, look in the -pf file, but unlikely to be there. It looks like a concatenated name, the LOAD can be somewhere unexpected. Check for any LOAD in the original code. It may not have been migrated for some reason.

#20 Updated by Roger Borrello almost 2 years ago

Galya B wrote:

Is initialization-file (progress-medium) specified in the client bootstrap configs for the FWD client? It is supposed to call EnvironmentDaemon.setDefaultEnvironment and set defaultEnv instead of calling load.

Yes, it uses a user_client.xml specified in the directory:

<node type="client">
   <client>
      <project token="gui" />
      <cmd-line-option initialization-file="progress-medium.ini" />
      <logging path="../logs/gui_%uos_%pid_%uf_%g.log" rotationLimit="500000" rotationCount="4" />
   </client>
</node>

So that explains how the default environment is setup.

As for appname-DEV-HV01.ini, look in the -pf file, but unlikely to be there. It looks like a concatenated name, the LOAD can be somewhere unexpected. Check for any LOAD in the original code. It may not have been migrated for some reason.

I believe I have the reports still around, so I'll find it.

In any case, I see the Progress behavior is to give an error when USE is performed, without a LOAD. This little test shows "The USE of x.ini failed (4452)" on Progress:

message "using x.ini no-error".
use "x.ini" no-error.
message "using x.ini".
use "x.ini".

So I need to find the LOAD.

#21 Updated by Roger Borrello almost 2 years ago

Roger Borrello wrote:

I believe I have the reports still around, so I'll find it.

I had the 7z file, but the files in callgraph are very small, so something must have gone wrong. Is EnvironmentalDaemon.load() where every LOAD would pass through? I debugged server startup, but I may have missed one of the clients, although I can only picture the web client being what might execute LOAD, not an app server.

#22 Updated by Galya B almost 2 years ago

Roger Borrello wrote:

Roger Borrello wrote:

I believe I have the reports still around, so I'll find it.

I had the 7z file, but the files in callgraph are very small, so something must have gone wrong. Is EnvironmentalDaemon.load() where every LOAD would pass through? I debugged server startup, but I may have missed one of the clients, although I can only picture the web client being what might execute LOAD, not an app server.

Any OE code can use LOAD. To USE an env, the code should either LOAD, or have the startup param. Can you simply search in the original OE code for LOAD? If you find the mechanism of loading the file in the original setup, it would be easier to reason about the FWD conversion.

#23 Updated by Roger Borrello almost 2 years ago

Galya B wrote:

Any OE code can use LOAD. To USE an env, the code should either LOAD, or have the startup param. Can you simply search in the original OE code for LOAD? If you find the mechanism of loading the file in the original setup, it would be easier to reason about the FWD conversion.

I tried to use prowin.exe -p useit.p -ininame p.ini where p.ini was a copy of the C:\progress\oe116_64\bin\progress.ini. The useit.p contains:

message "using env1".
use "env1".
message "used env1".

I get error 4452 trying to use and no load before it. This is very similar to how the customer application is structured, but does not fail in the same manner. In the reports, I see all the places where load is being performed in the application code, and I am not hitting any breakpoint in EnvironmentDaemon.load(), even when debugging the initialization of the web client.

#24 Updated by Galya B almost 2 years ago

Don't debug FWD, we need to debug their OE code running on Progress to understand what hasn't been migrated to FWD. If you specify -ininame p.ini cmd line, then you can't load env1. It should be use p.ini.

My point was to do a plain text search in their original code to find the LOAD uses.

#25 Updated by Greg Shah almost 2 years ago

My point was to do a plain text search in their original code to find the LOAD uses.

Don't use plain text search. Use FWD Analytics. The language statements support will show you EVERY location of LOAD in the application and there will be no false positives (matches to the text load that are really something else) or false negatives (missed matches because of some weirdness in the text matching like case-sensitivity or otherwise). For something simple like LOAD, false negatives are unlikely but false positiives are very likely. Just use FWD Analytics, it is why we made it.

#26 Updated by Galya B almost 2 years ago

Does FWD Analytics work over a file directory with original OE code or does it need the app loaded in FWD?

#27 Updated by Greg Shah almost 2 years ago

It is a developer tool that operates on 4GL source code. If that code is what is running in OE, then we are getting a true picture.

Roger mentioned "reports" in #8353-23, which is probably a reference to FWD Analytics. If that is correct, then he should be making a plan to look at these locations in OE not in FWD. If he has a debuggable environment on OE (unfortunately, not always the case) that could be used or those locations could be instrumented with logging.

#28 Updated by Roger Borrello almost 2 years ago

Galya B wrote:

Don't debug FWD, we need to debug their OE code running on Progress to understand what hasn't been migrated to FWD. If you specify -ininame p.ini cmd line, then you can't load env1. It should be use p.ini.

I'm pretty sure everything has been migrated. I can use the analytics to determine what might be performing the load, and can set breaks in the legacy code, to see. However, it appears I have to attach to the process at a certain point in execution, so if the load happens during initialization, I wouldn't be able to catch it (unless there is a debug technique I don't know about, which is highly likely).

Greg Shah wrote:

Roger mentioned "reports" in #8353-23, which is probably a reference to FWD Analytics. If that is correct, then he should be making a plan to look at these locations in OE not in FWD. If he has a debuggable environment on OE (unfortunately, not always the case) that could be used or those locations could be instrumented with logging.

Exactly. I had to get a 5TB external drive to allow me space to hold the database, which is 91GB.

The load [KW_LOAD] (36 in 20 files) is reported, and almost have are the LOAD ""., so it's about 18 spots in 20 files. I can break in those to find this.

#29 Updated by Roger Borrello almost 2 years ago

I found the actual load. I set about 8 breakpoints, and caught it. The EnvironmentDaemon.load() pushes the environment named without any .ini extension, but in EnvironmentDaemon.use(), it attempts to retrieve the environment with a .ini extension.

My update in 4517b makes sure the environment named with .ini at the end, so it does get found, but could do the opposite... make sure there isn't any .ini during the push, and pull.

#30 Updated by Roger Borrello almost 2 years ago

  • % Done changed from 0 to 100
  • Status changed from WIP to Review

I have committed revision 15388 of branch 4517b, which ensures that the environment name for INI does not contain an extension both when creating the Stanza INI during LOAD, and when finding it via USE.

I would appreciate if there could be a review.

I also looked for some LOAD/USE testcases, but don't find any. Marian, can you point me towards them?

#31 Updated by Galya B almost 2 years ago

I haven't worked on StanzaIni.java, but with all the questions around adding the registry fallback for Linux, I probably know enough to help. But Roger, can you formulate with an example what is the problem found on trunk and what is the solution provided in 4517b. There are certain parts that don't make sense to me, like removing the original file extension with envName = env.substring(0, lastIndex);.

#32 Updated by Greg Shah almost 2 years ago

Agreed. We need to see the 4GL testcase(s) that show the difference between OE and FWD. Then we can assess your changes.

#33 Updated by Roger Borrello almost 2 years ago

Greg Shah wrote:

Agreed. We need to see the 4GL testcase(s) that show the difference between OE and FWD. Then we can assess your changes.

This is the testcase:

load "env1".
use "env1".
GET-KEY-VALUE SECTION "section1" KEY "key1" VALUE keyval.
message "keyval="keyval.
use "".
unload "env1".

and the env1.ini contains:
[section1]
key1 = value11
key2 = value12
[section2]

OE will show keyval=value11. In trunk, there will be an NPE since the trunk EnvironmentDaemon.load() has:

...
      boolean isIniType = EnvironmentReader.TYPE_INI.equalsIgnoreCase(baseKey);
      if (!isIniType && !PlatformHelper.isUnderWindowsFamily())
      {
         envs = envFallbackMap;
         env = env.toLowerCase();
         envAcc = new FallbackEnvironmentReader(env, clientStorage, baseKey.toLowerCase());
      }
...

My updates to protect the .toLowerCase(), but we really need to be able to determine that "env1" is an ini Type. OE does that. We will create a fallback environment, but there isn't any data backing it.

This branch contains:

      boolean isIniType = EnvironmentReader.TYPE_INI.equalsIgnoreCase(baseKey) || 
                          (env.toLowerCase().endsWith(".ini"));
      if (!isIniType && !PlatformHelper.isUnderWindowsFamily())
      {
         envs = envFallbackMap;
         env = env.toLowerCase();
         baseKey = (baseKey != null) ? baseKey.toLowerCase() : baseKey;
         envAcc = new FallbackEnvironmentReader(env, clientStorage, baseKey);
      }
      else if (isIniType)
      {
         envs = envIniMap;
         envAcc = new StanzaIni(env, directory, flagNew, isReadOnly);
      }

but it needs to not just look to see if the environment passed has .ini extension, it needs to determine if there is a file backing it before falling back.

I could use a clue on how to do that check here, so we can find "env1.ini", even though just "env1" is passed in.

#34 Updated by Roger Borrello almost 2 years ago

  • % Done changed from 100 to 90
  • Status changed from Review to WIP

#35 Updated by Marian Edu almost 2 years ago

Roger,

I've pushed some unit tests for this environment INI support - you can find them under tests/base_language/environment_registryINI_access in testcases rev #1628.

#36 Updated by Greg Shah almost 2 years ago

I could use a clue on how to do that check here, so we can find "env1.ini", even though just "env1" is passed in.

I would create a method public static boolean isIniFile(String filename) in StanzaIni which should implement the same testing logic the OE uses. You can read the code in that class to see how it accesses the filesystem. Use the same techniques.

Galya will review it to confirm that it doesn't cause problems with her work in #4065.

#37 Updated by Galya B almost 2 years ago

According to the section Notes in LOAD statement the default LOAD without BASE-KEY "INI" first looks in the registry, so the current trunk implementation is correct in this regard. On Linux the registry is the fallback env, so the new part of the condition is not correct (looking for the ext). Actually what's missing is that the FallbackEnvironmentReader needs to check if the 'registry key' exists and then fallback to StanzaIni (but only if BASE-KEY key-name is not specified).

#38 Updated by Galya B almost 2 years ago

Greg Shah wrote:

I could use a clue on how to do that check here, so we can find "env1.ini", even though just "env1" is passed in.

I would create a method public static boolean isIniFile(String filename) in StanzaIni which should implement the same testing logic the OE uses. You can read the code in that class to see how it accesses the filesystem. Use the same techniques.

Galya will review it to confirm that it doesn't cause problems with her work in #4065.

Roger can add anything necessary, I'll take it into consideration on merge.

The actual method should be checking for the 'registry key' via the fallback env.

#39 Updated by Roger Borrello almost 2 years ago

Galya B wrote:

According to the section Notes in LOAD statement the default LOAD without BASE-KEY "INI" first looks in the registry, so the current trunk implementation is correct in this regard. On Linux the registry is the fallback env, so the new part of the condition is not correct (looking for the ext). Actually what's missing is that the FallbackEnvironmentReader needs to check if the 'registry key' exists and then fallback to StanzaIni (but only if BASE-KEY key-name is not specified).

So in load, before calling FallbackEnvironmentReader it would need to check for 'registry key'? What section/key would be checked in clientStorage for that indication?

In my testing I have found that loading "env3.txt" and then "env3" ignores the 2nd load, because the values I read came from "env3.txt", so it much check that an environment is already in place, and doesn't override it, nor keep a 2nd because of extensions being different. I'll have to add a check for exiting env before putting another of the same name.

#40 Updated by Galya B almost 2 years ago

Roger Borrello wrote:

Galya B wrote:

According to the section Notes in LOAD statement the default LOAD without BASE-KEY "INI" first looks in the registry, so the current trunk implementation is correct in this regard. On Linux the registry is the fallback env, so the new part of the condition is not correct (looking for the ext). Actually what's missing is that the FallbackEnvironmentReader needs to check if the 'registry key' exists and then fallback to StanzaIni (but only if BASE-KEY key-name is not specified).

So in load, before calling FallbackEnvironmentReader it would need to check for 'registry key'? What section/key would be checked in clientStorage for that indication?

ClientStorageImpl relies on two types of KeyValueStorage. Both UserPreferences and LocalStorageAccessor will need a new method along the lines of doesSectionExist that will lookup for the path instead of a specific key. The path is concat by first adding env and baseKey in FallbackEnvironmentReader and then fwdUser and storageId in KeyValueStorage. LocalStorageAccessor will require a trip to the browser and probably some weird parsing of the whole storage content. For UserPreferences it's an easy check with preferences.nodeExists(section).

In my testing I have found that loading "env3.txt" and then "env3" ignores the 2nd load, because the values I read came from "env3.txt", so it much check that an environment is already in place, and doesn't override it, nor keep a 2nd because of extensions being different. I'll have to add a check for exiting env before putting another of the same name.

You can load many envs, but the values will be taken from the env that is in use. If the env has been loaded with startup args it's probably in use.

Roger, now that we've identified the problem and the solution, I can take over the task if you don't mind. I wasn't aware of that lookup rule, when first implemented the fallback env. If the customer's code uses BASE-KEY "INI" this is not replicable.

#41 Updated by Greg Shah almost 2 years ago

  • Assignee changed from Roger Borrello to Galya B

#42 Updated by Roger Borrello almost 2 years ago

  • Assignee changed from Galya B to Roger Borrello

Galya B wrote:

You can load many envs, but the values will be taken from the env that is in use. If the env has been loaded with startup args it's probably in use.

The point I was making was when you have multiple LOAD in effect with the same environment name, but different files, the first one loaded is used.

Take this example:

load "env3.txt" dir inidir base-key "INI".
load "env3" dir inidir base-key "INI".
use "env3".
GET-KEY-VALUE SECTION "section1" KEY "key1" VALUE keyval.
message "keyval="keyval.

GET-KEY-VALUE SECTION "" KEY "key1" VALUE keyval.
message "keyval="keyval.

GET-KEY-VALUE SECTION "section1" KEY "" VALUE keyval.
message "keyval="keyval.

GET-KEY-VALUE SECTION "section" KEY DEFAULT VALUE keyval.
message "keyval="keyval.
unload "env3".

use "".
GET-KEY-VALUE SECTION "section1" KEY "key1" VALUE keyval.
message "keyval="keyval.

The contents of env3.txt is:

[section1]
key1 = value3txt1
key2 = value3txt2
[section2]

The contents of env3.ini is:

[section1]
key1 = value3ini1
key2 = value3ini2
[section2]

When executed, 4GL shows:

keyval= value3txt1
keyval= section1,section2
keyval= key1,key2
keyval= ?
keyval= ?

When executed, FWD (trunk) shows:

keyval= value3ini1
keyval= section1
keyval= key1,key2
keyval= ?
keyval= ?

So the wrong env3 is used. I don't think the 2nd load should have replaced the first.

Thanks for straightening this one out.

#43 Updated by Galya B almost 2 years ago

The logic with checking the registry before using ini should be implemented for regular Windows Registry as well, so it was an oversight from the beginning. Hope you can test Windows too.

#44 Updated by Greg Shah almost 2 years ago

  • Assignee changed from Roger Borrello to Galya B

Roger: Please add your tests into the Testcases unit tests.

#45 Updated by Galya B almost 2 years ago

  • Assignee changed from Galya B to Roger Borrello

Roger Borrello wrote:

Galya B wrote:

You can load many envs, but the values will be taken from the env that is in use. If the env has been loaded with startup args it's probably in use.

The point I was making was when you have multiple LOAD in effect with the same environment name, but different files, the first one loaded is used.

Take this example:
[...]

The contents of env3.txt is:
[...]

The contents of env3.ini is:
[...]

When executed, 4GL shows:
[...]

When executed, FWD (trunk) shows:
[...]

So the wrong env3 is used. I don't think the 2nd load should have replaced the first.

Thanks for straightening this one out.

I've said that the file extension should not be removed in 4517b. Otherwise this type of issues occur.

I'll implement #8353-40 and #8353-43 and the issue in #8353-33 should be fixed.

#46 Updated by Galya B almost 2 years ago

  • Assignee changed from Roger Borrello to Galya B
  • % Done changed from 90 to 0

#47 Updated by Galya B almost 2 years ago

Roger Borrello wrote:

Greg Shah wrote:

Agreed. We need to see the 4GL testcase(s) that show the difference between OE and FWD. Then we can assess your changes.

This is the testcase:
[...]
and the env1.ini contains:
[...]

OE will show keyval=value11. In trunk, there will be an NPE since the trunk EnvironmentDaemon.load() has:
[...]

My updates to protect the .toLowerCase(), but we really need to be able to determine that "env1" is an ini Type. OE does that. We will create a fallback environment, but there isn't any data backing it.

This branch contains:
[...]
but it needs to not just look to see if the environment passed has .ini extension, it needs to determine if there is a file backing it before falling back.

I could use a clue on how to do that check here, so we can find "env1.ini", even though just "env1" is passed in.

Where do you test Progress? I can't use the registry methods in the #5600 env, because I don't have admin rights and I get The LOAD of (key-value file) failed. (4450).

I can't find it anywhere in the documentation that loading env env1 will read from the file env1.ini and I want to test it.

#48 Updated by Roger Borrello almost 2 years ago

  • Assignee changed from Galya B to Roger Borrello

#49 Updated by Galya B almost 2 years ago

Galya B wrote:

Where do you test Progress?

Not FWD.

#50 Updated by Galya B almost 2 years ago

My bad. This is a Progress VM. I didn't remember there is one.

#51 Updated by Greg Shah almost 2 years ago

Don't we have a Windows based 4GL dev system at multiple customers? Use one that is associated with the customer that inspired this task.

#52 Updated by Galya B almost 2 years ago

Greg Shah wrote:

Don't we have a Windows based 4GL dev system at multiple customers? Use one that is associated with the customer that inspired this task.

I've never used it. Does it come with admin rights? Otherwise the registry can't be used it seems.

#53 Updated by Roger Borrello almost 2 years ago

Galya B wrote:

I've never used it. Does it come with admin rights? Otherwise the registry can't be used it seems.

We do not have admin rights on those environments. The VM, yes.

#54 Updated by Galya B almost 2 years ago

Testing Progress 11.6.3:

1. Create a new ini env:

LOAD "env1" NEW BASE-KEY "INI".
USE "env1".

Creates an empty file env1.ini in the Progress dir.

2. Create a new registry env without any keys:

LOAD "env1" NEW.
USE "env1".

Doesn't create a registry section / key named env1, or ini file, but gets executed successfully.

3. Try to use a registry env created without any keys (after 2.):

LOAD "env1".
USE "env1".

Results in an error "The LOAD of env1 failed. (4450)".

4. Create a new registry env and put a key:

LOAD "env1" NEW.
USE "env1".
PUT-KEY-VALUE SECTION "section1" KEY "key1" VALUE "value1".

Creates a registry section HKEY_CURRENT_USER/env1/section1 key key1 and value value1.

5. Create a new ini env with a name ending with .ini and put a key:

LOAD "env1.ini" NEW.
USE "env1.ini".
PUT-KEY-VALUE SECTION "section1" KEY "key1" VALUE "value1".

Creates a registry section HKEY_CURRENT_USER/env1.ini/section1 key key1 and value value1.

6. Create a new ini env with a name ending with .ini and put a key:

LOAD "env1.ini" NEW BASE-KEY "INI".
USE "env1.ini".
PUT-KEY-VALUE SECTION "section1" KEY "key1" VALUE "value1".

Creates a file env1.ini in the Progress dir with section [section1] and key1=value1.

7. Use an old ini env with a name ending with .ini and read a key (after 6.):

LOAD "env1.ini" BASE-KEY "INI".
USE "env1".
GET-KEY-VALUE SECTION "section1" KEY "key1" VALUE valuevar.

Reads key1 in section [section1] from the file env1.ini in the Progress dir.

8. Create a new ini env with a name ending with .ext and put a key:

LOAD "env1.ext" NEW BASE-KEY "INI".
USE "env1.ext".
PUT-KEY-VALUE SECTION "section1" KEY "key1" VALUE "value1".

Creates a file env1.ext in the Progress dir with section [section1] and key1=value1.

9. Use an old ini env with a name ending with .ext and read a key (after 8.):

LOAD "env1.ext" BASE-KEY "INI".
USE "env1.ext".
GET-KEY-VALUE SECTION "section1" KEY "key1" VALUE valuevar.

Reads key1 in section [section1] from the file env1.ext in the Progress dir.

10. Use an old ini env with a name ending with .ext and read a key (after 8.):

LOAD "env1.ext" BASE-KEY "INI".
USE "env1".
GET-KEY-VALUE SECTION "section1" KEY "key1" VALUE valuevar.

Reads key1 in section [section1] from the file env1.ext in the Progress dir.

11. Create a new ini env with a name ending with .ini.ext and put a key:

LOAD "env1.ini.ext" NEW BASE-KEY "INI".
USE "env1.ini.ext".
PUT-KEY-VALUE SECTION "section1" KEY "key1" VALUE "value1".

Creates a file env1.ini.ext in the Progress dir with section [section1] and key1=value1.

12. Use an old ini env with a name ending with .ini.ext and read a key (after 11.):

LOAD "env1.ini.ext" BASE-KEY "INI".
USE "env1.ini.ext".
GET-KEY-VALUE SECTION "section1" KEY "key1" VALUE valuevar.

Reads key1 in section [section1] from the file env1.ext in the Progress dir.

13. Use an old ini env with a name ending with .ini.ext and read a key (after 11.):

LOAD "env1.ini.ext" BASE-KEY "INI".
USE "env1.ini".
GET-KEY-VALUE SECTION "section1" KEY "key1" VALUE valuevar.

Results in an error The LOAD of env1.ini failed. (4450).

14. Use an old ini env with a name ending with .ini.ext and read a key (after 11.):

LOAD "env1.ini.ext" BASE-KEY "INI".
USE "env1".
GET-KEY-VALUE SECTION "section1" KEY "key1" VALUE valuevar.

Results in an error The LOAD of env1 failed. (4450).

15. Create two registry envs with the same name and different base-key or lack thereof:

LOAD "env1" NEW BASE-KEY "test".
LOAD "env1" NEW.

Results in an error The LOAD of env1 failed. (4450). Every variation of loading two different envs with the same name leads to the same result.

16. Load first a new ini env and load an env with the same name after that:

LOAD "env1" NEW BASE-KEY "INI".
LOAD "env1.ini" NEW BASE-KEY "test".
USE "env1".
PUT-KEY-VALUE SECTION "section1" KEY "key1" VALUE "value1".

Creates a file env1.ini in the Progress dir with section [section1] and key1=value1.

17. Load first a new registry env and load an ini env with the same name after that:

LOAD "env1.ini" NEW BASE-KEY "test".
LOAD "env1" NEW BASE-KEY "INI".

Results in an error The LOAD of env1.ini failed. (4450).

18. Create two new ini envs with a name ending with .ini and .ext respectively and put a key:

LOAD "env1.ini" BASE-KEY "INI".
LOAD "env1.ext" BASE-KEY "INI".
USE "env1".
PUT-KEY-VALUE SECTION "section1" KEY "key1" VALUE "value1".

Creates two files env1.ext and env1.ini in the Progress dir and puts section [section1] with key1=value1 in one of the files env1.ext.

19. Create several new ini envs with a name ending with unusual extensions and put a key:

LOAD "env1.abc" BASE-KEY "INI".
LOAD "env1.wzc" BASE-KEY "INI".
LOAD "env1.ert" BASE-KEY "INI".
USE "env1".
PUT-KEY-VALUE SECTION "section1" KEY "key1" VALUE "value1".

Creates the last file env1.ert in the Progress dir and puts section [section1] with key1=value1 inside. On first attempt with a new env name, creates all files. After the files are deleted and the procedure re-executed, it creates only env1.ert, but from time to time one of the other files is also created (empty), it's not consistently reproducible.

#55 Updated by Galya B almost 2 years ago

Testing Progress 11.6.3:

20. Create a new registry env and call use with the same name, but different case:

LOAD "env1" NEW.
USE "ENV1".

Results in an error The LOAD of ENV1 failed. (4452). Note the error number is different from the other errors with similar text. The same result with reverted values for load and use (first uppercase, then lowercase).

So it seems env names are case-sensitive. I'm not sure why we have env.toLowerCase(), but it will be removed.

#56 Updated by Galya B almost 2 years ago

My tests show that BASE-KEY can be only one of the root keys for Windows: HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CURRENT_CONFIG or INI. In any other case running Progress in Windows LOAD returns the error 4450. Also, I wasn't able to actually use HKEY_LOCAL_MACHINE, HKEY_USERS even when starting as admin, it causes the error The PUT-KEY-VALUE failed. (4454).

Marian / Roger, can we confirm this behavior? I'm not sure if we want to migrate it. Also I'm not sure if Progress can be running on Linux and behave differently in this department.

This behavior is important though, when making conclusions based on the tests. I'll have to update #8353-54 to reflect it.

#57 Updated by Roger Borrello almost 2 years ago

Galya B wrote:

My tests show that BASE-KEY can be only one of the root keys for Windows: HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CURRENT_CONFIG or INI. In any other case running Progress in Windows LOAD returns the error 4450. Also, I wasn't able to actually use HKEY_LOCAL_MACHINE, HKEY_USERS even when starting as admin, it causes the error The PUT-KEY-VALUE failed. (4454).

Marian / Roger, can we confirm this behavior? I'm not sure if we want to migrate it. Also I'm not sure if Progress can be running on Linux and behave differently in this department.

This behavior is important though, when making conclusions based on the tests. I'll have to update #8353-54 to reflect it.

Marian, I don't see any tests in tests/base_language/environment_registryINI_access that utilize BASE-KEY. Is that possible to add, with some of the options Galya listed?

#58 Updated by Roger Borrello almost 2 years ago

  • Assignee changed from Roger Borrello to Galya B

#59 Updated by Galya B over 1 year ago

Our Win Registry implementation by default checks for the value (when no BASE-KEY specified) only in the root HKEY_CURRENT_USER section, while in OE it checks multiple locations under HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE. Should we make FWD fully compatible with OE?

#60 Updated by Galya B over 1 year ago

There is a funky behavior in OE: create a key env1 directly in win registry under HKEY_LOCAL_MACHINE/SOFTWARE and run a procedure to LOAD (without NEW) + USE env1 and PUT a key value; reload the regisry and the value is actually written to HKEY_CURRENT_USER/Software. Rinse and repeat, same result. But the env is loaded originally from HKEY_LOCAL_MACHINE.

#61 Updated by Greg Shah over 1 year ago

Should we make FWD fully compatible with OE?

Yes

I can't speak for the funky behavior from #8353-60. That seems like a bug in OE. Normally we don't implement things that seem to be bugs, except when an application actually relies upon it. Then it is not a bug, it is a "quirk".

#62 Updated by Galya B over 1 year ago

Greg Shah wrote:

Should we make FWD fully compatible with OE?

Yes

I can't speak for the funky behavior from #8353-60. That seems like a bug in OE. Normally we don't implement things that seem to be bugs, except when an application actually relies upon it. Then it is not a bug, it is a "quirk".

I agree, it looks like a bug in the version I'm testing with. I won't look more into it, it shouldn't be reproduced either.

#63 Updated by Marian Edu over 1 year ago

Roger Borrello wrote:

Marian, I don't see any tests in tests/base_language/environment_registryINI_access that utilize BASE-KEY. Is that possible to add, with some of the options Galya listed?

Roger, the team will add some more tests including use of BASE-KEY, will reply back when available in testcases.

#64 Updated by Galya B over 1 year ago

My observations on the file extensions:
  • If the environment has one dot in the name, the part after the dot is considered file extension and allows the environment to be used without it. For example LOAD "file.ext". and then USE "file". This applies to any ext, not only .ini. Also this applies only when the environment is considered INI file, i.e. the fallback of LOAD without BASE-KEY "INI" when the key is not found in the registry, or when BASE-KEY "INI" is specified explicitly.
  • If the environment has multiple dots in the name, only the full name can be used in USE.
  • LOAD with NEW BASE-KEY "INI" creates a new file with the given name and adds .ini as file extension only when the name doesn't have a dot in the name. For example LOAD "test." NEW BASE-KEY "INI" creates a file test, but LOAD "test" NEW BASE-KEY "INI" creates a file test.ini.
  • Loading an old ini file works without specifying the ext, e.g. LOAD "test". will load test.ini. This is not the behavior for any other ext type. LOAD "test" BASE-KEY "INI". doesn't load the file test without the ini extension.
  • The Procedure Editor creates a cache of all environments loaded and often gives ambiguous results. For example creating a registry env (key) with name test, later continuously refers to the same env even if it's deleted or an attempt to create an ini with the same name is executed by a different procedure. This behavior persists until the editor is closed. I think the same cache may be present in production environments. Needs to be kept in mind.

#65 Updated by Galya B over 1 year ago

About case-sensitivity:
  • OE is case-sensitive between LOAD and USE, but not when it comes to loading the key from registry or the file in Windows. In other words LOAD "Test.ini". loads the file test.ini, but USE "test.ini" doesn't work afterwards and fails with 4452.

The following procedure successfully loads the file test.ext twice with different cases and once the registry key test.ext and then expects a case-sensitive match to use the env.

LOAD "Test.EXT" BASE-KEY "INI".
LOAD "TeSt.ext" 
LOAD "TeST.ext" BASE-KEY "INI".
USE "TeSt.ext".

#66 Updated by Galya B over 1 year ago

All the above comments for USE (case-sensitivity and file extension) apply to UNLOAD too.

#68 Updated by Roger Borrello over 1 year ago

Galya, the situation where the application gives NPE noted in #8353-33 has been "re-reported" by the customer. I created branch 4517c since I could not rebase 4517b to the current trunk (so my changes were preserved). However, you had noted that my changes were probably not accurate, so if that branch isn't helpful it could be abandoned.

#69 Updated by Galya B over 1 year ago

Roger Borrello wrote:

Galya, the situation where the application gives NPE noted in #8353-33 has been "re-reported" by the customer. I created branch 4517c since I could not rebase 4517b to the current trunk (so my changes were preserved). However, you had noted that my changes were probably not accurate, so if that branch isn't helpful it could be abandoned.

I've started work in 8353a and there is only a little left to be completed. I'll try to schedule this work to one of the next days and we can discuss it again.

#70 Updated by Greg Shah over 1 year ago

  • Assignee deleted (Galya B)

The work to complete the implementation, as documented by Galya:

  • confirm the native code is not case sensitive when doing checks in Win Registry
  • implement the new JNI method Registry.hasKey
  • convert permissions exception to an OE error

Also available in: Atom PDF