tcunit/TcUnit-Runner

Load correct version of TwinCAT

Closed this issue · 20 comments

Today, TcUnit-Runner tries to load the TwinCAT-version that the project is created in such as:
log.Info("Using the TwinCAT remote manager to load TwinCAT version '" + this.tcVersion + "'...");
ITcRemoteManager remoteManager = dte.GetObject("TcRemoteManager");
remoteManager.Version = this.tcVersion;

where tcVersion is for example 3.1.4022.32.

Now, for example loading 3.1.4022.32 on a machine that only has 3.1.4022.30 does not return any error. Should it be this way, or should the program abort? Or should it be a configuration parameter to select whether the user:

  • Wants to override the project version of TwinCAT
  • Or simply ignore the TwinCAT project version

One thing that has to be considered if is the user has pinned/locked the version of TwinCAT in the project file itself.

Running TcUnit-Runner on a machine that has 4022.30 but where the project is 4022.32 results in:
2020-09-05 14:59:59 - In TwinCAT project file, found TwinCAT version 3.1.4022.32
2020-09-05 14:59:59 - In Visual Studio solution file, found visual studio version 12.0
2020-09-05 14:59:59 - ... none existing Visual Studio process found. Creating new instance of visual studio DTE.
2020-09-05 14:59:59 - Trying to load the Visual Studio Development Tools Environment (DTE) version 'VisualStudio.DTE.12.0' ...
2020-09-05 15:00:02 - ...SUCCESSFUL!
2020-09-05 15:00:02 - Using the TwinCAT remote manager to load TwinCAT version '3.1.4022.32'...
2020-09-05 15:00:19 - No task name provided. Assuming only one task exists
2020-09-05 15:00:19 - Found task with name 'PlcTask'
2020-09-05 15:00:37 - Setting target NetId to '5.44.93.176.1.1'
2020-09-05 15:00:38 - Enabling boot project and setting BootProjectAutostart on 5.44.93.176.1.1
2020-09-05 15:01:12 - Waiting for results from TcUnit...

I like the TcUnit-Runner pretty much as it is, it is opening a solution and doing what it is supposed to do. It is great that it doesn't require much configuration but kinda works out-of-the box. This made it rather easy for me to switch from an internal Unittest framework to TcUnit.

That being said, the usecase exists and is important. However, it might even be more involved than what you mention. What comes to my mind is Variants (supported since Twincat 4024), dealing with specific Twincat Library Versions (I tend to avoid placeholders as they can cause some nesty problems on occasions) and installing PLC references.
In my opinion this should be handled by a seperate tool. I prefer tools that do 1 job and do this one well.

I would vote for a error with the reason. e.x. TwinCat version not available or Project pinned to version xxx

Then you can repair or change your project with another tool or by hand.

But then you know where the problem was and you do not have to spend hours for debugging

With pinned TwinCAT projects I fully agree. However, with un-pinned projects there are a lot of users that build/compile their projects with whatever is the latest version that they have available on that machine.
It would put limitation on those users building their software this way.

I guess we would have to check whether a project is actually pinned, and return an error if that version is not installed. The good thing with pinning is that we don't need to select a version with the remote manager, as the XAE does this automatically. I don't know at which step it would fail (if at all) though doing this.

Can you look into this @Beidendorfer ?

"I guess we would have to check whether a project is actually pinned, and return an error if that version is not installed." I did a Pull Request with the check of Pinned Version. I hope it is the right way to participate

@Beidendorfer, yes I've seen the PR but haven't had time to look into it quite yet. I'll do my very best to check it out during the weekend. Thank you so much for looking into this. It's highly appreciated.

@Beidendorfer What "nasty" problems have you had with using placeholders?

@sagatowski I don´t get your point with the placeholders?
Are there still problems or generally a better implementation?

@Beidendorfer no no no, I was just curious of your problems of placeholder, because you mentioned this:
"I tend to avoid placeholders as they can cause some nesty problems on occasions"

@sagatowski I personally have not had so many problems with placeholders. I think the question refers to the post from stefanbesler

I like the TcUnit-Runner pretty much as it is, it is opening a solution and doing what it is supposed to do. It is great that it doesn't require much configuration but kinda works out-of-the box. This made it rather easy for me to switch from an internal Unittest framework to TcUnit.

That being said, the usecase exists and is important. However, it might even be more involved than what you mention. What comes to my mind is Variants (supported since Twincat 4024), dealing with specific Twincat Library Versions (I tend to avoid placeholders as they can cause some nesty problems on occasions) and installing PLC references.
In my opinion this should be handled by a seperate tool. I prefer tools that do 1 job and do this one well.

Correct?

@Beidendorfer You're right, sorry, it's been a busy weekend and I'm too tired to even think :-)

With reference to PR#9:

Just finished testing and it all seems to behave fine.
If I have a VM with 4022.30 loaded:
Use case #1 - Not pinned. Loads 4022.30, all fine.
Use case #2 - Pinned to 4022.30. Loads 4022.30. Still works fine.
Use case #3 - Pinned to 4022.29. Doesn't load project and warns the user that the required version is not installed.

The only use case I think is a little weird is this:
Use case #4 - VM with 4022.30 and 4024.11 installed. Project is saved with 4022.32, but it's not pinned. Then I get this:

C:\Code\tcunit_runner\Debug>TcUnit-Runner.exe -v "C:\Code\TcUnit-Verifier_TwinCAT\TcUnit-Verifier_TwinCAT.sln"
2020-11-15 17:39:09 - TcUnit-Runner build: 0.9.2.0
2020-11-15 17:39:09 - TcUnit-Runner build date: 2020-11-15
2020-11-15 17:39:09 - Visual Studio solution path: C:\Code\TcUnit-Verifier_TwinCAT\TcUnit-Verifier_TwinCAT.sln
2020-11-15 17:39:09 -
2020-11-15 17:39:09 - In TwinCAT project file, found TwinCAT version 3.1.4022.32
2020-11-15 17:39:09 - In Visual Studio solution file, found visual studio version 12.0
2020-11-15 17:39:09 - Version is pinned: False
2020-11-15 17:39:09 - Trying to load the Visual Studio Development Tools Environment (DTE) version 'VisualStudio.DTE.12.0' ...
2020-11-15 17:39:19 - ...SUCCESSFUL!
2020-11-15 17:39:19 - Using the TwinCAT remote manager to load TwinCAT version '3.1.4022.32'...
2020-11-15 17:39:26 - Load TwinCAT version: 3.1.4022.30
2020-11-15 17:42:37 - No task name provided. Assuming only one task exists
2020-11-15 17:42:37 - Found task with name 'PlcTask'
2020-11-15 17:43:03 - Setting target NetId to '127.0.0.1.1.1'
2020-11-15 17:43:03 - Enabling boot project and setting BootProjectAutostart on 127.0.0.1.1.1
2020-11-15 17:43:31 - Waiting for results from TcUnit...
2020-11-15 17:43:58 - Application interrupted by user
2020-11-15 17:43:58 - Closing the Visual Studio Development Tools Environment (DTE)...
2020-11-15 17:44:18 - Exiting application...

I would expect it to load the project with the latest version (4024.11) at this time, and not 4022.30. And I can't quite figure out why it does so.

Anyways I'll merge this into the main, and I think it would be interesting to have a separate issue to handle the case what we should do with a project that opens on a machine that doesn't have the right version of TwinCAT installed but that is not pinned.

@Beidendorfer I'll merge the PR #9, and I'm open for a discussion of how to handle usecase #4, so I'll leave this issue open.
My suggestion for the case when a version of TwinCAT is not installed, and it is not pinned, is to just simply make sure to use the latest installed TwinCAT version.

My guess is that the remote manager always takes the last version of the main version 3.1.4022.xx or 3.1.4020.xx

Okay 3 default behaviour :

1.) Check if Version is Pinned and the TwinCat Version is installed -> Start TcRunner with Pinned Version
If not applicable, TcRunner will be aborted due to the pinned version

2.) Check if Version from Project File .tsproj is installed -> Start TcRunner with Project Version

3.) if Project Version (.tsproj) not installed used the last installed Version -> Start TcRunner Last installed Version

To Point 3) What happens is the last installed version is lower then the Project version (.tsproj) ?
Should we then continue or rather stop with a error?

2020-11-15 17:39:19 - Using the TwinCAT remote manager to load TwinCAT version '3.1.4022.32'...
2020-11-15 17:39:26 - Load TwinCAT version: 3.1.4022.30

@sagatowski I think we don´t save the Project after finihed the build.
This means that when we make changes they are only temporary.

In my projects, where I use the Automation Interface, I save them. This means that if I start a lower version 22.30 instead of 22.32, the project file (.tsproj) is pulled down to 22.30 and saved.

But this is not the case with TcRunner, because TcRunner only does a check.

Correct?

May I add one default behavior that should be considered (before @Beidendorfer no. 1): Add a commandline argument to force a specific version. If this one is not installed, abort TcUnitRunner.

On my Testsystem I have multiple agents (some with only 1 TwinCAT Versions installed, some with several). Each agent carries Jenkins node labels with the TwinCAT versions that should be used and I dynamically generate stages in Jenkins for these labels that run sequentially. For now, I wrote a script that modifies .tsproj and removes pins such that TcUnitRunner uses the version that I actually want for a specific agent and a specific stage, but it would be great to just have a commandline option

the remote manager always takes the last version of the main version

Only if Options > TwinCAT > XAE Environment > TwinCAT Version default is not set to a specific version

@stefanbeser: I am impressed with your CI Jenkins, VW, TwinCat setup. I would like to know more about problems and best Pratice ;)

Back to the question:
I can understand the wish.

Add a commandline argument to force a specific version. If this one is not installed, abort TcUnitRunner

The option force TCUnitRunner to Version xx must overwrite the option pinned version and the Version from the .tsproj file

I don't see a problem with that, but if you forced a TCUnitRunner to a version but know that at the end of the test the .tsproj is modified to the forced version, maybe the pinned version is changed.

For me it is no problem, because TCUnitRunner is only for unit test.
It is not a TcBuildApplication Program

how does the rest see it?

I would like to create a possible solution and put it up for discussion

Hi! I agree with both of you. I think we should go with @Beidendorfer suggestion. On the question what we should do on 3) if the project is saved with a newer version than what is available, TcUnit-Runner should still just use the latest version anyways (and maybe possible just do an entry in the print-log to indicate that the latest versions installed is older than the one in the tsproj, but not more than that.

Also like @stefanbesler suggestion to have a command-line option to override which version should be used (and make sure to abort the tcunit-running if the version provided in the command line is not installed, just as if it was a pinned version). The current command-line arguments right now are:

1. VisualStudioSolutionFilePath=", "The full path to the TwinCAT project (sln-file)", v
2. VisualStudioSolutionFilePathTcUnitTaskName=", "[OPTIONAL] The name of the task running TcUnit defined under \"Tasks\"", t
3. AmsNetId=", "[OPTIONAL] The AMS NetId of the device of where the project and TcUnit should run", a
4. help", h => showHelp = h)

I suggest we add
5. TwinCATVersion=","[OPTIONAL]" The TwinCAT version to be used to load the TwinCAT project", tc

I think the documentation for TcUnit-Runner (https://tcunit.org/tcunit-runner-user-manual/) needs to be updated once these changes are made to clarify this default behaviour.

Hi I pushed in my a Fork a Version for TC Runner where I fixed Problem 4. If TwinCat Project is not pinned it used the last installed Version from the system.

Added an option -tc to force TC Runner to this Version. If this Version is not Installed TcRunner Aborts
With the .bat file I'm not sure if I did it right.
I did not checked if i can unter 3 Options?? I only test the -tc Version

Can someone please take a look at the .bat in relation to the option?

@echo off
rem -----------------------------------------------------------------------------
rem Batch script for launching TcUnit-Runner
rem For documentation see: www.tcunit.org
rem -----------------------------------------------------------------------------
rem Instructions:
rem Set the below variable TCUNIT_RUNNER_INSTALL_DIRECTORY to where TcUnit-Runner was
rem installed. This should normally be left at default and not changed
rem (default C:\Program Files (x86)\TcUnit-Runner)
SET TCUNIT_RUNNER_INSTALL_DIRECTORY=C:\Program Files (x86)\TcUnit-Runner

rem The parameters that can be supplied are:
rem -t [OPTIONAL] The name of the task running TcUnit defined under "Tasks".
rem If this is not provided, it's assumed that only one task exists in the TwinCAT project.
rem -a [OPTIONAL] The AMS NetId of the device of where the project and TcUnit should run.
rem If this is not provided, the local AMS NetId is assumed (127.0.0.1.1.1)
rem -tc[OPTIONAL] A fix TwinCat Version is not provided! TcUnit-Runner tries to start with Project Version
rem A fix TwinCat Version is using:

SET TCUNIT_TASK_NAME=
SET TCUNIT_AMSNETID=
SET TCUNIT_TCVERSION_TO_USE=

CALL :Process_Parameters %1, %2, %3, %4

rem Create parameter call to TcUnit-Runner
SET TCUNIT_RUNNER_PARAMETERS=
IF DEFINED TCUNIT_TASK_NAME (
SET TCUNIT_RUNNER_PARAMETERS=%TCUNIT_RUNNER_PARAMETERS% --TcUnitTaskName=%TCUNIT_TASK_NAME%
)
IF DEFINED TCUNIT_AMSNETID ( SET TCUNIT_RUNNER_PARAMETERS=%TCUNIT_RUNNER_PARAMETERS% --AmsNetId=%TCUNIT_AMSNETID% ) IF DEFINED TCUNIT_TCVERSION_TO_USE (
SET TCUNIT_RUNNER_PARAMETERS=%TCUNIT_RUNNER_PARAMETERS% --TwinCATVersion=%TCUNIT_TCVERSION_TO_USE%
)

SET TCUNIT_RUNNER_EXECUTABLE_COMPLETE_PATH=%TCUNIT_RUNNER_INSTALL_DIRECTORY%\TcUnit-Runner.exe

rem Check that the TcUnit-Runner executable exists
IF NOT EXIST "%TCUNIT_RUNNER_EXECUTABLE_COMPLETE_PATH%" (
echo The configured search path "%TCUNIT_RUNNER_INSTALL_DIRECTORY%" for TcUnit-Runner does not exist!
GOTO Exit
)

IF NOT DEFINED TCUNIT_TASK_NAME (
echo Task name of the TcUnit task not provided! Assuming only one task in TwinCAT solution
) ELSE (
echo A TcUnit task name has been provided, using: %TCUNIT_TASK_NAME%
)

IF NOT DEFINED TCUNIT_AMSNETID (
echo AmsNetId to run TwinCAT/TcUnit is not provided! Assuming TwinCAT/TcUnit will run locally '127.0.0.1.1.1'
) ELSE (
echo An AmsNetId has been provided, using: %TCUNIT_AMSNETID%
)

IF NOT DEFINED TCUNIT_TCVERSION_TO_USE (
echo A fix TwinCat Version is not provided! TcUnit-Runner tries to start with Project Version
) ELSE (
echo A fix TwinCat Version is using: %TCUNIT_TCVERSION_TO_USE%
)

rem Find the visual studio solution file.
FOR /r %%i IN (*.sln) DO (
SET VISUAL_STUDIO_SOLUTION_PATH="%%i"
)

rem Error handling of finding the files.
IF NOT DEFINED VISUAL_STUDIO_SOLUTION_PATH (
echo Visual studio solution file path does not exist!
GOTO Exit
) ELSE (
echo VISUAL_STUDIO_SOLUTION_PATH found!
echo The filepath to the visual studio solution file is: %VISUAL_STUDIO_SOLUTION_PATH%
)

rem Call TcUnit-Runner
"%TCUNIT_RUNNER_EXECUTABLE_COMPLETE_PATH%" --VisualStudioSolutionFilePath=%VISUAL_STUDIO_SOLUTION_PATH% %TCUNIT_RUNNER_PARAMETERS%

rem %errorlevel% is a system wide environment variable that is set upon execution of a program
echo Exit code is %errorlevel%

EXIT /B %errorlevel%

rem This function process the parameters
:Process_Parameters

rem First parameter
IF "%~1" == "-t" (
SET TCUNIT_TASK_NAME=%2
)
IF "%~1" == "-T" (
SET TCUNIT_TASK_NAME=%2
)
IF "%~1" == "-a" (
SET TCUNIT_AMSNETID=%2
)
IF "%~1" == "-A" (
SET TCUNIT_AMSNETID=%2
)

IF "%~1" == "-tc" (
SET TCUNIT_TCVERSION_TO_USE=%2
)
IF "%~1" == "-TC" (
SET TCUNIT_TCVERSION_TO_USE=%2
)

rem Second parameter
IF "%~3" == "-t" (
SET TCUNIT_TASK_NAME=%4
)
IF "%~3" == "-T" (
SET TCUNIT_TASK_NAME=%4
)
IF "%~3" == "-a" (
SET TCUNIT_AMSNETID=%4
)
IF "%~3" == "-A" (
SET TCUNIT_AMSNETID=%4
)
IF "%~3" == "-tc" (
SET TCUNIT_TCVERSION_TO_USE=%4
)
IF "%~3" == "-TC" (
SET TCUNIT_TCVERSION_TO_USE=%4
)

GOTO:EOF

:Exit
echo Failed!
EXIT /B 1`

@Beidendorfer Can you create a pull request from your fork, and also do a sync before doing the pull request? (so that the repos are synced with each other. I just noticed that your fork is two commits behind the main).

Solved in commit 02c036e and by PR #11.