Just for the knowledge I just want to see how WRITE triggers execute for the query below. Is it possible to see them?.
FOR EACH Customer EXCLUSIVE-LOCK WHERE NAME = "Go Fishing Ltd":
ASSIGN Customer.Balance = 600.
END.
Add:
-clientlog path/to/log.log -logginglevel 4 -logentrytypes 4GLTrace
to your startup command.
This will create a log of all of the calls that your code makes.
For more information: https://knowledgebase.progress.com/articles/Knowledge/P9893
You can also use the LOG-MANAGER system handle within your code to dynamically control the logging at runtime:
https://docs.progress.com/bundle/openedge-abl-troubleshoot-applications/page/LOG-MANAGER-system-handle-attributes-and-methods.html
but for simple purposes like this it is easier to just add the startup parameters.
Watch the log-manager show the write trigger being executed on the sports2020 database:
def var clog as char no-undo.
def var lclog as longchar no-undo.
assign
clog = guid + '.log'.
log-manager:logfile-name = clog
log-manager:log-entry-types = '4gltrace:5,4glmessages'
.
for each Customer exclusive-lock where name = 'Go Fishing Ltd':
Customer.Balance = Customer.Balance + 1. // write trigger only fires when record changes
end.
log-manager:close-log().
copy-lob from file clog to lclog.
message string( lclog ).
https://abldojo.services.progress.com/?shareId=62978a833fb02369b25479f0
Relevant snippet from the output:
4GLTRACE Return from Main Block "Customer Customer" [sports2020trgs/wrcust.p]
Related
In an unit test, I need to verify that the program skip locked records when processing a table.
I have been unable to setup a locked records because the test can't lock itself which make a lot of sense.
Here is a sample of what I'm trying to achieve.
DEV VAR v_isCommitted AS LOGI NO-UNDO.
DEF VAR hl AS HANDLE NO-UNDO.
DEF BUFFER bufl FOR tablename.
hl = BUFFER bufl:HANDLE.
LOCKED_RECORDS:
DO TRANSACTION ON ERROR UNDO, LEAVE LOCKED_RECORDS:
/*Setup : Create record not committed yet*/
CREATE tablename.
ASSIGN tablename.fields = fieldsvalue.
/*ACT : Code I'm trying to test*/
/*...some code...*/
v_isCommitted = hl:FIND-BY-ROWID(ROWID(tablename), EXCLUSIVE-LOCK, NO-WAIT)
AND AVAILABLE(bufl)
AND NOT LOCKED(bufl).
/*...some code touching the record if it is commited...*/
/*ASSERT : program left new record tablename AS IS.*/
END.
The problem is that the record is available and not locked to the test because it was created by it.
Is there a way I could have the test lock a record from itself so the act part can actually skip the record like it was created by someone else?
Progress: 11.7.1
A session can not lock itself. So you will need to start a second session. For example:
/* code to set things up ... */
/* spawn a sub process to try to lock the record */
os-command silent value( substitute( '_progres -b -db &1 -p lockit.p -param "&2" && > logfile 2>&&1', dbname, "key" )).
In lockit.p use session:parameter to get the key for the record to test (or hard code it I suppose).
Or, as mentioned in the comments below:
/* locktest.p
*/
define variable lockStatus as character no-undo format "x(20)".
find first customer exclusive-lock.
input through value( "_progres /data/sports120/sports120 -b -p ./lockit.p" ).
repeat:
import unformatted lockStatus.
end.
display lockStatus.
and:
/* lockit.p
*/
find first customer exclusive-lock no-wait no-error.
if locked( customer ) then
put "locked".
else
put "not locked".
quit.
I'm currently trying to connect a Lua Script with a GS WebApp. The connection is working but due to my lack of knowledge in GScripting I'm not sure why it isn't saving my data correctly.
In the Lua side I'm just passing in a hard-code a random name and simple numerical userid.
local HttpService = game:GetService("HttpService")
local scriptID = scriptlink
local WebApp
local function updateSpreadSheet ()
local playerData = (scriptID .. "?userid=123&name:Jhon Smith")
WebApp = HttpService:GetAsync(playerData)
end
do
updateSpreadSheet()
end
On the Google Script side i'm only saving the data on the last row and then add the value of the userid and the name.
function doGet(e) {
console.log(e)
// console.log(f)
callName(e.parameter.userid,e.parameter.name);
}
function callName(userid,name) {
// Get the last Row and add the name provided
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(sheet.getLastRow() + 1,1).setValues([userid],[name]);
}
However, the only data the script is saving is the name, bypassing the the userid for reasons I have yet to discover.
setValues() requires a 2D array and range dimensions should correspond to that array. The script is only getting 1 x 1 range and setValues argument is not a 2D array. Fix the syntax or use appendRow
sheet.getRange(sheet.getLastRow() + 1,1,1,2).setValues([[userid,name]]);
//or
sheet.appendRow([userid,name])
References:
appendRow
I'm currently implementing a SBT plugin for Gatling.
One of its features will be to open the last generated report in a new browser tab from SBT.
As each run can have a different "simulation ID" (basically a simple string), I'd like to offer tab completion on simulation ids.
An example :
Running the Gatling SBT plugin will produce several folders (named from simulationId + date of report generaation) in target/gatling, for example mysim-20140204234534, myothersim-20140203124534 and yetanothersim-20140204234534.
Let's call the task lastReport.
If someone start typing lastReport my, I'd like to filter out tab-completion to only suggest mysim and myothersim.
Getting the simulation ID is a breeze, but how can help the parser and filter out suggestions so that it only suggest an existing simulation ID ?
To sum up, I'd like to do what testOnly do, in a way : I only want to suggest things that make sense in my context.
Thanks in advance for your answers,
Pierre
Edit : As I got a bit stuck after my latest tries, here is the code of my inputTask, in it's current state :
package io.gatling.sbt
import sbt._
import sbt.complete.{ DefaultParsers, Parser }
import io.gatling.sbt.Utils._
object GatlingTasks {
val lastReport = inputKey[Unit]("Open last report in browser")
val allSimulationIds = taskKey[Set[String]]("List of simulation ids found in reports folder")
val allReports = taskKey[List[Report]]("List of all reports by simulation id and timestamp")
def findAllReports(reportsFolder: File): List[Report] = {
val allDirectories = (reportsFolder ** DirectoryFilter.&&(new PatternFilter(reportFolderRegex.pattern))).get
allDirectories.map(file => (file, reportFolderRegex.findFirstMatchIn(file.getPath).get)).map {
case (file, regexMatch) => Report(file, regexMatch.group(1), regexMatch.group(2))
}.toList
}
def findAllSimulationIds(allReports: Seq[Report]): Set[String] = allReports.map(_.simulationId).distinct.toSet
def openLastReport(allReports: List[Report], allSimulationIds: Set[String]): Unit = {
def simulationIdParser(allSimulationIds: Set[String]): Parser[Option[String]] =
DefaultParsers.ID.examples(allSimulationIds, check = true).?
def filterReportsIfSimulationIdSelected(allReports: List[Report], simulationId: Option[String]): List[Report] =
simulationId match {
case Some(id) => allReports.filter(_.simulationId == id)
case None => allReports
}
Def.inputTaskDyn {
val selectedSimulationId = simulationIdParser(allSimulationIds).parsed
val filteredReports = filterReportsIfSimulationIdSelected(allReports, selectedSimulationId)
val reportsSortedByDate = filteredReports.sorted.map(_.path)
Def.task(reportsSortedByDate.headOption.foreach(file => openInBrowser((file / "index.html").toURI)))
}
}
}
Of course, openReport is called using the results of allReports and allSimulationIds tasks.
I think I'm close to a functioning input task but I'm still missing something...
Def.inputTaskDyn returns a value of type InputTask[T] and doesn't perform any side effects. The result needs to be bound to an InputKey, like lastReport. The return type of openLastReport is Unit, which means that openLastReport will construct a value that will be discarded, effectively doing nothing useful. Instead, have:
def openLastReport(...): InputTask[...] = ...
lastReport := openLastReport(...).evaluated
(Or, the implementation of openLastReport can be inlined into the right hand side of :=)
You probably don't need inputTaskDyn, but just inputTask. You only need inputTaskDyn if you need to return a task. Otherwise, use inputTask and drop the Def.task.
I want to get the count of status(Pass/Fail) of all testcases present in QC by checking the execution grid.
What is the method to retrieve the status and execution date of a test case ?
Currently I am only able to get the test case name.
Code:
Set treeMgr = gTDConn.TestSetTreeManager
Set tstTree = treeMgr.NodeByPath(TestSetPath)
Set tstFactory = tstTree.testSetFactory
Set tsetList = tstFactory.NewList("")
For Each tset In tsetList
msgbox tset.Name
next
I'm running Python 3.2.2 and writing some code to test sockets. For the ease of testing, I'm using Tkinter to add a GUI interface. What I have yet to figure out is how to update the information in the grid I'm using. I want to update "host2" and "port2" in the functions "change1" and "change3" in the following code:
import socket
from tkinter import *
import tkinter.simpledialog
root = Tk()
root.title("Server")
root.iconbitmap("etc.ico")
root.geometry("350x100+200+200")
frame = Frame(root)
host1 = Label(frame,text="Host: ").grid(row=0,column=0)
port1 = Label(frame,text="Port: ").grid(row=1,column=0)
HOST = 'localhost'
PORT = 11111
STATUS = 'EMPTY'
host2 = Label(frame,text=HOST,width=10).grid(row=0,column=1)
port2 = Label(frame,text=PORT,width=10).grid(row=1,column=1)
status1 = Label(root,text=STATUS)
status1.pack(side=RIGHT,padx=2,pady=2)
def change1():
global HOST
HOST= tkinter.simpledialog.askstring(title="Host",prompt="Enter the IP of the Host.")
host2.grid_forget()
def change3():
global PORT
PORT= tkinter.simpledialog.askinteger(title="Port",prompt="Enter the Port of the IP.")
port2.grid_forget()
def go1():
global HOST
global PORT
home = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
home.bind((HOST, PORT))
home.listen(1)
conn, addr = home.accept()
print (addr)
while 1:
data = conn.recv(1024)
if not data: break
global STATUS
STATUS = data.decode('UTF-8')
conn.send(bytes('Received "Hello World"','UTF-8'))
conn.close()
global status1
status1.pack_forget()
status1.pack(side=RIGHT,padx=2,pady=2)
change = Button(frame, text="Change Host", width=10,command=change1).grid(row=0,column=2)
change2 = Button(frame, text="Change Port", width=10,command=change3).grid(row=1,column=2)
go = Button(frame, text="GO!",command=go1,width =10).grid(row=2,column=2)
frame.pack(side=LEFT)
mainloop()
Any help on the matter would be much appreciated! Thanks!
Your problems begin with this line:
host1 = Label(frame,text="Host: ").grid(row=0,column=0)
What you are doing is creating a label, using grid to place the label on the screen, then assigning host1 the result of the grid() command, which is the empty string. This makes it impossible to later refer to host1 to get a reference to the label.
Instead, you need to save a reference to the label. With that reference you can later change anything you want about the label:
host1 = Label(frame, text="Host: ")
host1.grid(row=0, column=0)
...
if (something_has_changed):
host1.configure(text="Hello, world!")
Take it from someone with over a decade of experience with tk, it's better to separate your widget creation and layout. Your layout will almost certainly change over the course of development and it's much easier to do that when all your layout code is in one place. My layouts may change a lot but my working set of widgets rarely does, so I end up only having to change one block of code rather than dozens of individual lines interleaved with other code.
For example, my code generally looks roughly like this:
labell = tk.Label(...)
label2 = tk.Label(...)
entry1 = tk.Entry(...)
label1.grid(...)
label2.grid(...)
entry1.grid(...)
Of course, I use much better variable names.
First, before going in depth with this problem. I want to highlight out a few things. In this line.
host2 = Label(frame,text=HOST,width=10).grid(row=0,column=1)
I want you to separate the gridding part from the declaration of the variable. Because it will create a No Type object that you cant work with. It will create many problems in the future that may take a lot of your time. If you have any variables structured like this that are not just going to be served as lines of text. Change the structure of that of that variable to the structure that I described above. Anyways, going back to what you where saying but in more depth is that to change the text of the Labels. What I would do if its going to be changed by function is in that function that you are wanting to change the text of the Label. Put in lines like this.
host2['text'] = 'Your New Text'
port2['text'] = 'Your New Text'
# or
host2.configure(text = 'Your New Text')
port2.configure(text = 'Your New Text')
This will change the text of your labels to the newly changed text or In other words replaces the text with the new text.