Expecco Plugin API/en: Unterschied zwischen den Versionen
Cg (Diskussion | Beiträge) |
Cg (Diskussion | Beiträge) |
||
Zeile 128: | Zeile 128: | ||
The following simple plugin shall install a post-testplan-execute action, which sends a REST message to an (alien) quality management system. |
The following simple plugin shall install a post-testplan-execute action, which sends a REST message to an (alien) quality management system. |
||
[[Datei:Plugin_SystemBrowser1.png|200px|thumb|right|Class Browser & Class Search Menu]] |
[[Datei:Plugin_SystemBrowser1.png|200px|thumb|right|Class Browser & Class Search Menu]] |
||
* open a Class Browser via "''Extras''" |
* open a Class Browser via "''Extras''" → "''Tools''" → "''Class Browser''", and find the "<code>AbstractUserPlugin</code>" class: |
||
** right click into the top-left category-list and select the "''Find Class...''" menu item, |
** right click into the top-left category-list and select the "''Find Class...''" menu item, |
||
** enter: "<code>UserPlugin</code>" into the now appearing class-search dialog |
** enter: "<code>UserPlugin</code>" into the now appearing class-search dialog |
||
Zeile 147: | Zeile 147: | ||
** press "''Accept''" (the green bar on the left) or choose "''Accept''" from the codeview's right-button menu (<kbd>CTRL-s</kbd> will also do) |
** press "''Accept''" (the green bar on the left) or choose "''Accept''" from the codeview's right-button menu (<kbd>CTRL-s</kbd> will also do) |
||
** concratulations: you have created a new class!. |
** concratulations: you have created a new class!. |
||
* create the minimum required code via the class-menus "''Generate''" |
* create the minimum required code via the class-menus "''Generate''" → "''Required Protocol''" menu function. |
||
** right click into the second-top-left class list and select the "''Generate''" menu item, |
** right click into the second-top-left class list and select the "''Generate''" menu item, |
||
** a submenu appears; select the last item named "''Required Protocol''" |
** a submenu appears; select the last item named "''Required Protocol''" |
||
Zeile 155: | Zeile 155: | ||
** select the "<code>pluginUUID</code>" method in the top-right list. |
** select the "<code>pluginUUID</code>" method in the top-right list. |
||
** in the codeview: select the "<code>self shouldImplement</code>" piece of code (left click and move), |
** in the codeview: select the "<code>self shouldImplement</code>" piece of code (left click and move), |
||
** then open the |
** then open the context menu (right button) and choose "''More''" → "''Misc''" → "''Insert new UUID''" |
||
** place single quotes around the UUID string |
** place single quotes around the UUID string |
||
Aktuelle Version vom 3. September 2019, 09:31 Uhr
Inhaltsverzeichnis
Introduction[Bearbeiten]
Expecco is built on an open architecture, which allows for additional functions to be added dynamically. Customers, eXept and third parties can therefore add more functions via plugins.
This document is for plugin developers and describes the plugin API and required protocol which has to be implemented by a plugin.
Expecco Plugin API[Bearbeiten]
The expecco plugin API allows for both graphical and non-graphical extensions to be built for and added to expecco. Plugins are allowed to add items to the top menu, to the toolbar, to popup-menus in the tree or the diagram editor, and to add additional pages (tabs) to the testplan and testcase editors, and to the settings dialog. Plugins can also add custom fields to any artefact, for example to remember links or ids for external program interfacing.
Plugins which are placed in or under the "plugins
" directory are automatically loaded and installed when expecco is started. Other plugins can be installed at any later time via the settings dialog. You can slightly speed up the initial startup of expecco, by placing unused plugins into a separate folder.
Usually, plugins consist of dlls (dynamic link libraries) which contain binary compiled code. However, it is also possible to directly load source-code files, as expecco includes a compiler to generate bytecode from loaded program text.
Plugins are developed and created using the free Smalltalk/X (ST/X) development IDE, and usually (but not required to be) deployed as binary class libraries. The ST/X IDE includes a project builder to generate self-installing deployable dll-packages. Alternatively, small plugins and additional classes can also be deployed in source form via the IDE's "fileOut" operation.
A plugin's protocol consists of a number of methods which MUST, in addition to optional methods which CAN be implemented.
The entry point of every plugin is represented by a plugin class, a subclass of Expecco::AbstractPlugin
.
Immediately after loading, that classes' initialize
method is called,
followed by a number of other calls into the plugin, by which expecco collects various aspects from the plugin:
Initialization & Release[Bearbeiten]
- void initialize (optional class method)
Invoked right after loading, before any of the methods below is called. Can be used to initialize files, connections, or check for other required packages to be loaded correctly. If redefined, do not forget to call"super initialize"
. Be careful to not block or perform long computations in this method, as it is invoked unconditionally - even if the plugin is never used later. If such computations or connections are needed, it might be better to perform them lazily later, when the plugin is first instantiated (by redefining either the classes"new"
method, or the instances"initialize"
method).
- void loadRequiredPackages (optional class method)
Invoked by the initialize method. Gives the plugin a change to load any additional required packages (for example: telecommunication class libraries). Normally, this is not required as binary class packages usually pull in any required packages automatically.
- void release (optional class method)
Invoked right before the plugin is unloaded (if it is so via the settings dialog). Should close any open files, connections and remove any temporary data-files which might have been created by the plugin, but not which are not associated to a single browser instance. Notice that this is a class side method - it is invoked if the plugin-class is to be released (i.e. if the plugin itself is unloaded), not when an individual instance for a browser window is to be released (see below).
- void pluginRelease (optional instance method)
Invoked when the owning browser is closed. Should close any open files, connections and remove any temporary data-files which might have been created by the plugin for this particular browser window.
Startup, Registration and Queries[Bearbeiten]
- String pluginName (required class method)
Should return the plugin's name. This is the name shown in the list of loaded plugins (in the plugin settings dialog).
- String pluginInfo (required class method)
Should return the plugin's short description. Must return some user readable info about what the plugin does (also for the plugin settings dialog).
- UUID pluginUUID (required class method)
Must return the plugin's unique UUID. This id should be hardcoded into the plugin to return the same constant value forever. It is needed to detect upgrades or duplicate plugin classes.
- Class[] pluginClasses (required class method)
Should return a collection of classes, which comprise the plugin. (used in the plugin settings dialog, and to unload a plugin).
- (String Symbol)[] pluginSettingsList (optional class method)
Should return a collection of 2-element arrays, each defining an additional tab in the settings application. The first element will be used as the name (in the settings-dialog's tree), the second entry must be the name of the class which implements the tabs GUI. It must be a subclass of ApplicationModel.
- Image pluginMenuIcon (optional class method)
Can be defined to return a bitmap image; this is shown in the plugin-menu. Its size should be 16x16 pixels.
Menu Queries[Bearbeiten]
All of the above have been class methods. Once registered, one plugin instance is created for every open browser window. This allows for a plugin to keep context specific data (such as last used directory or settings) on a per-window basis. However, most plugins don't do this, but instead keep their state in class variables which are shared by all browser windows. The instance interface is:
- Boolean pluginBrowserMenuIsVisible (optional instance method)
Should return true, if this plugin has any visible menus for the browser (either topMenu or toolbar-menu).
- MenuItem[] pluginToolbarItemList (optional instance method)
A list of items to add to the toolbar menu.
- MenuSpec pluginBrowserMenu (optional instance method)
Can be defined to return a menuspec; this menu will be built into the plugin-menu as a separate submenu. Menuspec methods can be created easily using the ST/X MenuEditor tool.
- MenuSpec pluginBrowserMainMenu (optional instance method)
Can be defined to return a menuspec; this menu will be sliced into the main-menu. Menuspec methods can be created easily using the ST/X MenuEditor tool.
- MenuSpec pluginHelpBrowserMenu (optional instance method)
Can be defined to return a menuspec; this menu will be built into the help-plugin-menu as a separate submenu. Use the ST/X MenuEditor tool to create menuspec methods.
- MenuSpec pluginMenuItemsFor: what forElement: anElement (optional instance method)
Can be defined to return a menuspec which is added to the right-click (popup) menu of an element. The argument "what" is either#diagram
or#tree
; the "anElement" argument is a tree item element (blockdescription, testplan, resource, etc.) or a diagram element (step, connection, pin, etc.).
If any menu items were returned in one of the above menu-query methods, corresponding menu items which call back into the plugin-instance are added to either the top- or the toolbar menu.
Editor Page Queries[Bearbeiten]
In addition, plugins get a chance to add a private page to some editors, by returning an application instance (derived from ApplicationModel) from the following method:
- ApplicationModel pluginTabApplicationFor: aSymbol (optional instance method)
Can be defined to return an editor-specific additional tab-page. The argument specifies which editor is querying for the page; it is (currently) one of #testPlanEditor or #testCaseEditor (as of Mar 2010).
If an application was returned by the above entry, that application's GUI is added to the testplan- or testcase editor as a subapplication. The interface with the embedding editor is via the following protocol:
- void editedItem: aTestcaseItem (required)
The editor passes the item being edited (a testplan or testcase) to the plugin-app.
- String noteBookTabLabel (required)
the plugin's tab will get this label in the notebook.
- void whenModifiedDo: aBlock (required)
the plugin's tab should remember this block argument and invoke it as a callback, whenever the edited item (i.e. testcase or testplan) is modified by it. This is used to enable the "accept" buttons at the bottom of the editor.
Private Data/Fields of a Plugin[Bearbeiten]
Plugins can add private fields to testCases, testPlans and other artefacts. These additional fields are included in the XML, when the testSuite is stored or loaded.
- void propertyAt: aKey put: aString
To add a plugin-property. The key should be a string or symbol. Make sure that there are no conflicts, by prepending the plugin's name to the key. For example: 'JIRA.issueID' would be a good idea. Only string-values are allowed, If required, a string representation (i.e.printString
) should be used to ensure this. These properties are stored in the XML under the "properties" tag.
- String propertyAt: aKey
To retrieve a plugin-property. Use the same key as used when storing the property. Only string-values can be retrieved - if required, reconstruct the object using#readFrom:
.
As an alternative, some plugins keep private state as a taggedValue of the object; especially plugins which convert to/from other object representations do so. In contrast to the above properties, taggedValues are preserved in most external representations and can therefore usually be transported to/from other systems - especially to UML tools, such as enterprise architect or similar.
- Object taggedValueAt: aKey
to retrieve a tagged value
- void taggedValueAt: aKey put: anObject
to set a tagged value
- TaggedValue[] taggedValueProperties
to retrieve detail info for all known tagged values. The list consists of TaggedValue instances, which provides getter-methods for key, value and type.
Browser Hooks[Bearbeiten]
Plugins get informed about some actions in the browser window (the expecco main window).
- void pluginProjectOpened: aTestSuite (optional instance method)
Called right after the owning browser has opened (or loaded) a testSuite. Notice that the suite may have already been shown in another tab of the same or another browser.
- void pluginProjectReleased: aTestSuite (optional instance method)
Called right after the owning browser has closed or loaded a different suite. Notice that the suite may still be shown in another tab of the same or another browser.
- void pluginProjectReleasedInAllBrowsers: aTestSuite (optional instance method)
Called right after some browser has closed or loaded a different suite, AND this was the last reference to this suite. I.e. there is now no other browser or tab showing this suite.
Execution Hooks[Bearbeiten]
Plugins get informed about test executions. Notice that these entries are only called for regular test executions. Executions of a single block (via the test/demo-tab) are not forwarded to plugins. These callbacks can be used to update a database, send out user notifications or write a report in a private format.
- void pluginPreExecuteTestPlan: aTestPlanItem (optional instance method)
Called before a testplan is executed. Similar to a preaction, raising an error from within this preExecute-callback will cancel the testplan's execution.
- void pluginPreExecuteTestCase: aTestCaseItem (optional instance method)
Called before a testcase is executed. The log-argument (empty at this time) could be used to add a notification or other information feedback. Similar to a preaction, raising an error from within this preExecute-callback will cancel the testcases's execution (and the testplan's, if the testcase is not an optional one).
- void pluginPostExecuteTestCase: aTestCaseItem log: aLog (optional instance method)
Called after a testcase has been executed. The log-argument contains the detailed execution log information, and especially the outcome verdict.
- void pluginPostExecuteTestPlan: aTestPlan result: aTestResult (optional instance method)
Called after a testplan has been executed. The testResult instance contains detailed information about individual testcases and an overall result.
Sample Plugins[Bearbeiten]
The expecco installation includes some small example plugins in the "plugin/demoPlugins
"-folder. These can be used as templates to develop additional personal plugins.
- DemoPluginWithMenuOnly (file: "
Expecco__DemoPluginWithMenuOnly
") - does exactly what its name implies: it adds additional menu items which open an information notifier when invoked.
- DemoPluginWithSettingsGUI (file: "
Expecco__DemoPluginWithSettingsGUI
") - in addition to the above, this example also adds a settings dialog entry
- PrePostTestRunShellExecutionPlugin (file: "
Expecco__PrePostTestRunShellExecutionPlugin
") - implements dummy callbacks to monitor test execution.
Sample Plugin Creation Session[Bearbeiten]
The following simple plugin shall install a post-testplan-execute action, which sends a REST message to an (alien) quality management system.
- open a Class Browser via "Extras" → "Tools" → "Class Browser", and find the "
AbstractUserPlugin
" class:- right click into the top-left category-list and select the "Find Class..." menu item,
- enter: "
UserPlugin
" into the now appearing class-search dialog - an entry named "
Expecco::AbstractUserPlugin
" should be in the list; - select it and close the dialog with the "Find" button at the bottom (or double click on the "
Expecco::AbstractUserPlugin
" entry in the list).
- create a new subclass of "
AbstractUserPlugin
":- right click into the second-top-left class list and select the "New - Subclass" menu item,
- a definition template will appear; replace "
NewClass
" by "QMRestAnnouncePlugin
" and the category by "'Expecco-Plugin-QMRestAnnounce'
" (notice the quotes) - you should now have the folowing code on your screen:
"{ NameSpace: Expecco }" AbstractUserPlugin subclass:#QMRestAnnouncePlugin instanceVariableNames: classVariableNames: poolDictionaries: category:'Expecco-Plugin-QMRestAnnounce'
- press "Accept" (the green bar on the left) or choose "Accept" from the codeview's right-button menu (CTRL-s will also do)
- concratulations: you have created a new class!.
- create the minimum required code via the class-menus "Generate" → "Required Protocol" menu function.
- right click into the second-top-left class list and select the "Generate" menu item,
- a submenu appears; select the last item named "Required Protocol"
- this created a bunch of methods which are the minimum required methods for plugin classes.
- change the pluginUUID class method to provide a unique UUID
- select the "Class" radio control (in the Instance/Class radio group)
- select the "
pluginUUID
" method in the top-right list. - in the codeview: select the "
self shouldImplement
" piece of code (left click and move), - then open the context menu (right button) and choose "More" → "Misc" → "Insert new UUID"
- place single quotes around the UUID string
The next step is to save the plugin code to a file:
- select the "FileOut As..." menu function in the lass-menu.
- navigate to the expecco installation folder's "plugins" subfolder and save your code there.
Restart expecco.
Back to Plugins
Back to Online Documentation