Why is truffle returning <indexed> instead of the actual value of the event? - solidity

I have indexed some values on my events. When I run tests, why don't they show up ?
Example :
Events emitted during test:
---------------------------
Upgrade(_tokenId: <indexed>, _upgradeType: 1)
---------------------------
Why isn't it showing the token id?

The callback return object is different depending on if you create a global filter or a contract filter. You'd need to add your client code to give a better answer, but this looks like a global filter whose response separates out the event data (non-indexed fields) from the topics (the indexed fields). From the documentation:
data: String - contains one or more 32 Bytes non-indexed arguments of the log.
topics: Array of Strings - Array of 0 to 4 32 Bytes DATA of indexed log arguments. (In solidity: The first topic is the hash of the signature of the event (e.g. Deposit(address,bytes32,uint256)), except if you declared the event with the anonymous specifier.)
With a contract filter, you can get to each argument using args regardless if it's indexed or not.
Example:
var contractFilter = contractInstance.Upgrade({}, (e, r) => {
console.log(r.args._tokenId);
});

My truffle-assertions library can log all emitted events inside a transaction in the same way as truffle normally outputs them on error, except that it also displays indexed arguments' values correctly.
The library can be installed through npm
npm install truffle-assertions
Then, it can be imported at the top of your test file
const truffleAssert = require('truffle-assertions');
And finally it can be used to output all emitted events inside a transaction.
let result = contractInstance.function({from: account[0]});
truffleAssert.prettyPrintEmittedEvents(result);

Related

How to add a whole package to transport request by code?

My task is to do all these steps programmatically:
Create a new transport request, I managed to do this with TR_INSERT_REQUEST_WITH_TASKS
Add package content to the newly created transport, this is the part I am stuck in.
Release the transport, I managed to do this with TR_RELEASE_REQUEST
My problem is that I can manually add the package to the transport request via transaction SE03 and then release it with FM TR_RELEASE_REQUEST, but that is not the goal, everything from step 1 to 3 has to happen in one program execution if anyone can guide me how to do step 2 it would be very helpful, thanks in advance.
In your program, you must :
First get the list of objects which belong to the package, via the table TADIR (object in columns PGMID, OBJECT, OBJ_NAME, and package in column DEVCLASS)
And add these objects to the task or transport request via the non-released function modules TRINT_APPEND_COMM or TR_APPEND_TO_COMM_OBJS_KEYS.
To add the whole project into request you must first select all the objects from package and add them one by one. You can do it like this:
DATA: l_trkorr TYPE trkorr,
l_package TYPE devclass VALUE 'ZPACKAGE'.
cl_pak_package_queries=>get_all_subpackages( EXPORTING im_package = l_package
IMPORTING et_subpackages = DATA(lt_descendant) ).
INSERT VALUE cl_pak_package_queries=>ty_subpackage_info( package = l_package ) INTO TABLE lt_descendant.
SELECT pgmid, object, obj_name FROM tadir
INTO TABLE #DATA(lt_segw_objects)
FOR ALL ENTRIES IN #lt_descendant
WHERE devclass = #lt_descendant-package.
DATA(instance) = cl_adt_cts_management=>create_instance( ).
LOOP AT lt_segw_objects ASSIGNING FIELD-SYMBOL(<fs_obj>).
TRY.
instance->insert_objects_in_wb_request( EXPORTING pgmid = <fs_obj>-pgmid
object = <fs_obj>-object
obj_name = CONV trobj_name( <fs_obj>-obj_name )
IMPORTING result = DATA(result)
request = DATA(request)
CHANGING trkorr = l_trkorr ).
CATCH cx_adt_cts_insert_error.
ENDTRY.
ENDLOOP.
Note, that you cannot add objects that are already locked in another request, it will give you cx_adt_cts_insert_error exception. There is no way to unlock objects programmatically, only via SE03 tool.
You can check code behind, Write Transport Entry in SE80 right click on package menu.

How to share a variable between two routers module in cro?

I try to use Cro to create a Rest API that will publish messages in rabbitMQ. I would like to split my routes in different modules and compose them with an "include". But I would like to be able to share the same connection to rabbitMQ in each of those modules too. I try with "our" but it does not work :
File 1:
unit module XXX::YYY;
use Cro::HTTP::Router;
use Cro::HTTP::Server;
use Cro::HTTP::Log::File;
use XXX::YYY::Route1;
use Net::AMQP;
our $rabbitConnection is export = Net::AMQP.new;
await $rabbitConnection.connect;
my $application = route {
include <api v1 run> => run-routes;
}
...
File 2:
unit module XXX::YYY::Route1;
use UUID;
use Cro::HTTP::Router;
use JSON::Fast;
use Net::AMQP;
my $channel = $XXX::YYY::rabbitConnection.open-channel().result;
$channel.declare-queue("test_task", durable=> True );
sub run-routes() is export { ... }
Error message:
===SORRY!===
No such method 'open-channel' for invocant of type 'Any'
Thanks!
When you define your exportable route function you can specify arguments then in your composing module you can create the shared objects and pass them to the routes. For example in your router module :
sub run-routes ($rmq) is export{
route {
... $rmq is available in here
}
}
Then in your main router you can create your Queue and pass it in when including
my $rmq = # Insert queue creation code here
include product => run-routes( $rmq );
I've not tried this but I can't see any reason why it shouldn't work.
The answer by #Scimon is certainly correct, but it does not addresses the OP. On the other hand, the two comments by #ugexe and #raiph are spot-on, so I'll try to summarize them here and explain what's going on.
The error itself
This is the error:
Error message:
===SORRY!=== No such method 'open-channel' for invocant of type 'Any'
It indicates the invocant ($XXX::YYY::rabbitConnection) is of type Any, which is the type usually assigned to variables when they don't have a defined value; that is, basically, $XXX::YYY::rabbitConnection is not defined. It certainly is not since XXX::YYY is not included among the imported modules, as indicated by #ugexe.
The additioal problem indicated by the OP
That module was eliminated from the imported list because, as indicated by the OP
I certainly code it the wrong way because if i try to add use
XXX::YYY;, i get a Circular module loading detected error
But of course. since use XXX::YYY::Route1; which is file 2, is included in File 1.
The final solution is to reorganize files
That circular dependence probably points out to the fact that they should be in the same file, or else common code should be factored out to a third file, which would be eventually be included by both. So you should have something like
unit module XXX::YYY::Common;
use Net::AMQP;
our $rabbitConnection is export = Net::AMQP.new;
await $rabbitConnection.connect;
And then
use XXX::YYY::Common;
in both modules.

How to use insert_job

I want to run a Bigquery SQL query using insert method.
I ran the following code just like so:
JobConfigurationQuery = Google::Apis::BigqueryV2::JobConfigurationQuery
bq = Google::Apis::BigqueryV2::BigqueryService.new
scopes = [Google::Apis::BigqueryV2::AUTH_BIGQUERY]
bq.authorization = Google::Auth.get_application_default(scopes)
bq.authorization.fetch_access_token!
query_config = {query: "select colA from [dataset.table]"}
qr = JobConfigurationQuery.new(configuration:{query: query_config})
bq.insert_job(projectId, qr)
and I got an error as below:
Caught error invalid: Job configuration must contain exactly one job-specific configuration object (e.g., query, load, extract, spreadsheetExtract), but there were 0:
Please let me know how to use the insert_job method.
I'm not sure what client library you're using, but insert_job probably takes a JobConfiguration. You should create one of those and set the query parameter to equal your JobConfigurationQuery you've created.
This is necessary because you can insert various jobs (load, copy, extract) with different types of configurations to this one API method, and they all take a single configuration type with a subfield that specifies which type and details about the job to insert.
More info from BigQuery's documentation:
jobs.insert documentation
job resource: note the "configuration" field and its "query" subfield

Knowledge & Connect PHP API, Found object(Account or Answer) but contains only null fields

I'm facing some strange issues when I try to fetch(Connect PHP API)/searchContent(Knowledge Foundation API) following the tutorials/documentations.
Behaviour and output
Following the documentation, we initialize the API. The function error_get_last() (called after the fetch) states that the core read-only file (we are not allowed to modify it) contains an error:
Array ( [type] => 8 [message] => Undefined index: REDIRECT_URL [file] => /cgi-bin/${interface_name}.cfg/scripts/cp/core/framework/3.2.4/init.php [line] => 246 )
After initialization, we call the fetch function to retrieve an account. If we give a wrong ID, it returns an error:
Invalid ID: No such Account with ID = 32
Otherwise, furnishing a correct ID returns an Account object with all fields populated as NULL:
object(RightNow\Connect\v1_2\Account)#22 (25) {
["ID"]=>
NULL
["LookupName"]=>
NULL
["CreatedTime"]=>
NULL
["UpdatedTime"]=>
NULL
["AccountHierarchy"]=>
NULL
["Attributes"]=>
NULL
["Country"]=>
NULL
["CustomFields"]=>
NULL
["DisplayName"]=>
NULL
["DisplayOrder"]=>
NULL
["EmailNotification"]=>
NULL
["Emails"]=>
NULL
["Login"]=>
NULL
/* [...] */
["StaffGroup"]=>
NULL
}
Attempts, workaround and troubleshooting information
Configuration: The account used using the InitConnectAPI() has the permissions
Initialization: Call to InitConnectAPI() not throwing any exception(added a try - catch block)
Call to the fetch function: As said above, the call to RNCPHP\Account::fetch($act_id) finds the account (invalid_id => error) but doesn't manage to populate the fields
No exception is thrown on the RNCPHP::fetch($correct_id) call
The behaviour is the same when I try to retrieve an answer following a sample example from the Knowledge Foundation API : $token = \RNCK::StartInteraction(...) ; \RNCK::searchContent($token, 'lorem ipsum');
Using PHP's SoapClient, I manage to retrieve populated objects. However, It's not part of the standard and a self-call-local-WebService is not a good practice.
Code reproducing the issue
error_reporting(E_ALL);
require_once(get_cfg_var('doc_root') . '/include/ConnectPHP/Connect_init.phph');
InitConnectAPI();
use RightNow\Connect\v1_2 as RNCPHP;
/* [...] */
try
{
$fetched_acct = RNCPHP\Account::fetch($correct_usr_id);
} catch ( \Exception $e)
{
echo ($e->getMessage());
}
// Dump part
echo ("<pre>");
var_dump($fetched_acct);
echo ("</pre>");
// The core's error on which I have no control
print_r(error_get_last());
Questions:
Have any of you face the same issue ? What is the workaround/fix which would help me solve it ?
According to the RNCPHP\Account::fetch($correct_usr_id) function behaviour, we can surmise that the issue comes from the 'fields populating' step which might be part of the core (on which I have no power). How am I supposed to deal with this (fetch is static and account doesn't seem abstract) ?
I tried to use the debug_backtrace() function in order to have some visibility on what may go wrong but it doesn't output relevant information. Is there any way I can get more debug information ?
Thanks in advance,
Oracle Service Cloud uses lazy loading to populate the object variables from queried data using Connect for PHP APIs. When you output the result of an object, it will appear as each variable is empty, per your example. However, if you access the parameter, then it becomes available. This is only an issue when you try to print your object, like this example. Accessing the data should be immediate.
To print your object, like in your example, you would need to iterate through the object variables and access each one first. You could build a helper class to do that through reflection. But, to illustrate with a single field, do the following:
$acct = RNCPHP\Account::fetch($correctId);
$acct->ID;
print_r($acct); // Will now "show" ID, but none of the other fields have been loaded.
In the real world, you probably just want to operate on the data. So, even though you cannot "see" the data in the object, it's there. In the example below, we're accessing the updated time of the account and then performing an action on the object if it meets a condition.
//Set to disabled if last updated < 90 days ago
$acct = RNCPHP\Account::fetch($correctId);
$chkDate = time() - 7776000;
if($acct->UpdatedTime < $chkDate){
$acct->Attributes->PermanentlyDisabled = true;
$acct->save(RNCPHP\RNObject::SuppressAll);
}
If you were to print_r the object after the if condition, then you would see the UpdatedTime variable data because it was loaded at the condition check.

Sencha Touch 2 store is loaded multiple time [Maximum call stack size exceeded]

I'm having a weird problem with the Sencha Touch 2 Store class. Here is what I have:
A simple view PollsList that defines a list view (with a store attribute set to Polls). I've included the required store as follow: requires:['Polls'],
A store class Polls with a model attribute set to Poll and a dummy data attribute,
A model class named Poll (the simplest possible),
An app.js file with the following launch methode:
var pollsListView = Ext.create('PollsList');
Ext.Viewport.add(pollsListView);
Ext.Viewport.setActiveItem(pollsListView);
I've also included the stores: ['Polls'] declaration in the app.js as required.
Now, the weird thing is when I access the PollsList view, the Poll store is being loaded indefinitely, till I got a the following error:
Uncaught RangeError: Maximum call stack size exceeded sencha-touch.js:598
And the stack seems to loop on the following calls:
Ext.ClassManager.instantiate sencha-touch.js:6378
(anonymous function) sencha-touch.js:3198
(anonymous function) app/store/Polls.js:4
Ext.apply.globalEval sencha-touch.js:598
Ext.apply.globalEval sencha-touch.js:599
Ext.apply.loadScriptFile sencha-touch.js:7673
Ext.apply.require sencha-touch.js:7831
Ext.apply.syncRequire sencha-touch.js:7695
(anonymous function)
Any idea?
Seems weird, done many a times, but did not went wrong.
Any ways, try removing the setActiveItem as there is only one view and it will take it as active.
Remove the require line from the code, as it seems that currently it is not required though.(Just because i want to make this sample running).
Now, try initializing the store, as
var store = Ext.create("YourStore") //
var listControl = Ext.craeate("YourList" ,{store : "aboveCreatedStore" , ..... });
listControl.setData( {name :'hello'} ); // hoping the model is having one String type field
Ext.ViewPort.add(listControl);
Thats it...
The above given code is not a complete solution(its like a patch), but it is to make you know what wrong you are doing in your current code.