dbus api for sending GATT notification in bluez - bluetooth-lowenergy

Can someone tell me how to send GATT notifications using DBUS api's. Currently I am using bluez5.43. I am trying to register a service and send notifications. I have taken the reference of gatt-service.c which is present under the tools directory. When i look at the source code the characteristic has several characteristic methods registered with it. Out of those one is
GDBUS_ASYNC_METHOD("StartNotify", NULL, NULL, chr_start_notify)
but when i navigate to chr_start_notify,
I see the following
static DBusMessage *chr_start_notify(DBusConnection *conn, DBusMessage *msg, void *user_data)
{
return g_dbus_create_error(msg, DBUS_ERROR_NOT_SUPPORTED, "Not Supported");
}
Can anyone at least tell me is there any DBUS api for handling this, or dbus doesn't still support GATT server notifications?

I had the same issue and I found I workaround.
IF your client as enable notification upon your characteristic, this two following lines will set characteristic current value and BlueZ will handle it in stack and notify all subscribers
gatt_characteristic1_set_value(interface,value);
g_dbus_interface_skeleton_flush(G_DBUS_INTERFACE_SKELETON(interface));
You can, as an example, run a thread which call this function every X seconds, and your client will be notified every X seconds.
EDIT :
GattCharacteristic1 is a C DBus object create by gdbus-codegen from a xml file.
https://developer.gnome.org/gio/stable/gdbus-codegen.html
To help you, this is my xml file that I wrote according to BlueZ API doc.
<?xml version="1.0" encoding="UTF-8"?>
<node xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
<interface name="org.bluez.GattCharacteristic1">
<property name="UUID" type="s" access="read" />
<property name="Service" type="o" access="read" />
<property name="Value" type="ay" access="read" />
<property name="Notifying" type="b" access="read" />
<property name="Flags" type="as" access="read" />
<method name="ReadValue">
<arg name="options" type="a{sv}" direction="in" />
<arg name="value" type="ay" direction="out" />
</method>
<method name="WriteValue">
<arg name="value" type="ay" direction="in" />
<arg name="options" type="a{sv}" direction="in" />
</method>
<method name="StartNotify"/>
<method name="StopNotify"/>
</interface>
</node>
Once you have your xml file (named org.bluez.GattCharacteristic1.xml) which describe your GATT BlueZ object, use gbus-codegen to generate a "C DBus Object"
gdbus-codegen --generate-c-code org_bluez_gatt_characteristic_interface --interface-prefix org.bluez. org.bluez.GattCharacteristic1.xml
Now add c and h files into your sources codes
The following lines show HOW I create one GATT BlueZ characteristic upon DBus
const char* char_flags[] = {"read", "write", "notify", "indicate", NULL};
GattCharacteristic1* interface = gatt_characteristic1_skeleton_new();
// dbus object properties
gatt_characteristic1_set_uuid(interface,UUID);
gatt_characteristic1_set_service(interface,service_name);
gatt_characteristic1_set_value(interface,value);
gatt_characteristic1_set_notifying(interface,notifying);
gatt_characteristic1_set_flags(interface,flags);
// get handler (for example), please read doc from gdbus-codegen provide above.
g_signal_connect(interface,
"handle_read_value",
G_CALLBACK(dbus_client_on_handle_gatt_characteristic_read_value),
NULL);
// register new interface on object
g_dbus_object_skeleton_add_interface(object,G_DBUS_INTERFACE_SKELETON(interface));
// exports object on manager
g_dbus_object_manager_server_export(server_manager,object);
Please edit flags as you need. Keep a pointer upon interface object and use lines that I provides in the first answer. GBus doc is well documented, so I hope you will find every that you need.

Related

AD B2C SAML encryption error - Sequence contains no elements

I have followed the Microsoft documentation to encrypt the Assertions, but it gives me some error.
https://learn.microsoft.com/en-us/azure/active-directory-b2c/connect-with-saml-service-providers#enable-encrypted-assertions-optional
MetaData:
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://samltestapp2.azurewebsites.net">
<SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="true" protocolSupportEnumeration=" urn:oasis:names:tc:SAML:2.0:protocol">
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</NameIDFormat>
<AssertionConsumerService index="0" isDefault="true" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://samltestapp2.azurewebsites.net/SP/AssertionConsumer"/>
<KeyDescriptor use="encryption">
<KeyInfo xmlns="https://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>MIIDODCCAiCgAwIBAgIQEaP5fKYAQ6VBxbBPDi/IVDANBgkqhkiG9w0BAQsFADAv MS0wKwYDVQQDDCRlbmNyeXB0aW9uLm9kZmxkZW1vNS5vbm1pY3Jvc29mdC5jb20w HhcNMjEwMTE5MDQ0NDQzWhcNMjIwMTE5MDQ1NDQzWjAvMS0wKwYDVQQDDCRlbmNy eXB0aW9uLm9kZmxkZW1vNS5vbm1pY3Jvc29mdC5jb20wggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQClIee7OMFzTsZ3eDdTpDJOB0qsZCiGug3DtOoBrZsY pG6SNI1z7hPWiMJBJWaGrSPF/FcKS/RaOZi+G/Ht7RR+4qTzY2toqD7R7HYL8fyg lNx9d0n2RDRlgIHo9vtopw9fZaiEsvY3DiWWed9EvhQPyn9ewiZBWDLIlyOFT6oo jTiz6/xMneI96l8A7IQ+TAQbH2oUTaDTHksehmeVk3ExeWvgmfTzE812kzRMmWeP awlLJrCtRUu+NvxfDcmbv7bzxRfyDmM8gw7MIqELkIG4rNfFn0VvDnA7+oECm2DQ LKZgJZkAHJ+UWbKGj39CqOy6vkjA20pPtlhob5hp2qv1AgMBAAGjUDBOMA4GA1Ud DwEB/wQEAwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwHQYDVR0O BBYEFC1rpD8SwvSUXRvLJY072Vtf21LfMA0GCSqGSIb3DQEBCwUAA4IBAQBmD7MU vVXyX7nZ3h1rvhQUI4ryd3DUNdWZA2frdPm8xx6WQfEJKlYLKsRErcaCFXc9CGFK 2Ijfb9D0NxYo9JNJd9c2j2sDgZyxud5zn9xmSb3VZ42E+9y8NQz+UCYl6xlRIwwh vIdRpsVhmcXjcpW9Sos2kZ5wOnnROp6VwYTKSVDJyJYXPEz8is7Hhv5a7gsDW2pO GQAZXKxuH10IIpudxBszdwRGt3O945hyGsJNySljvvwoPiBwtZbSQbjpzmMGkFU9 BetAjN25+kSa8CNjv2wbLbs4boY/SmVTxMDHQpZ6k9fdms2Rdidl0o6BKKtjdkeE fH/F9XGJ2EbQKNwD</X509Certificate>
</X509Data>
</KeyInfo>
</KeyDescriptor>
</SPSSODescriptor>
</EntityDescriptor>
Relying party file:
<RelyingParty>
<DefaultUserJourney ReferenceId="SignUpOrSignInSAML" />
<UserJourneyBehaviors>
<JourneyInsights TelemetryEngine="ApplicationInsights" InstrumentationKey="xxxxxxxxxxxxxx" DeveloperMode="true" ClientEnabled="false" ServerEnabled="true" TelemetryVersion="1.0.0" />
<ScriptExecution>Allow</ScriptExecution>
</UserJourneyBehaviors>
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="SAML2"/>
<Metadata>
<Item Key="PartnerEntity">{Settings:MetadataURL}</Item>
<Item Key="ResponsesSigned">false</Item>
<Item Key="WantsEncryptedAssertions">true</Item>
<Item Key="IdpInitiatedProfileEnabled">true</Item>
</Metadata>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="surname" />
<OutputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="sub"/>
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
</RelyingParty>
Saml2AssertionIssuer:
<TechnicalProfile Id="Saml2AssertionIssuer">
<DisplayName>Token Issuer</DisplayName>
<Protocol Name="SAML2"/>
<OutputTokenFormat>SAML2</OutputTokenFormat>
<Metadata>
<!-- The issuer contains the policy name; it should be the same name as configured in the relying party application. B2C_1A_signup_signin_SAML is used below. -->
<Item Key="IssuerUri">{Settings:SignupSignInSAMLIssuerURI}</Item>
</Metadata>
<CryptographicKeys>
<Key Id="MetadataSigning" StorageReferenceId="B2C_1A_SamlIdpCert"/>
<Key Id="SamlAssertionSigning" StorageReferenceId="B2C_1A_SamlIdpCert"/>
<Key Id="SamlMessageSigning" StorageReferenceId="B2C_1A_SamlIdpCert"/>
<Key Id="SamlAssertionDecryption" StorageReferenceId="B2C_1A_SamlIdpCertEnc"/>
</CryptographicKeys>
<InputClaims/>
<OutputClaims/>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Saml-issuer"/>
</TechnicalProfile>
I am getting the below error. It is working properly without encryption, but if I enable the encryption getting that issue. Can someone suggest me a way to resolve this error.
Thanks #Saravana. WantsSignedAssertion indicates whether the technical profile requires all incoming assertions to be signed and SAML Response Assertion elements received by the relying party application must be signed. B2C requires both, the message and the assertion to be signed. If only assertion is signed, then it fails, and B2C does not accept it.
Please verify with the SAML decoder tool and see if both the assertion and the message are signed or not.
Please let us know if you need more help.
Reference:- https://github.com/azure-ad-b2c/saml-sp/blob/master/saml-rp-spec.md

ERP Operation not found error in WSO2EI DSS

I have created a REST - data service in WSO2EI an tried accessing through postman client tool, but I am getting this error.
End Point: http://LAPTOP-T4F1HOAM:8280/services/getStudRecNo?user_id=test8
The endpoint reference (EPR) for the Operation not found is /services/getStudRecNo?user_id=test8 and the WSA Action = null. If this EPR was previously reachable, please contact the server administrator.
Can anyone please help.
Thanks
dss code.
<data name="getStudRecNo" transports="http https local">
<description>get student unique id</description>
<config enableOData="false" id="mySchoolDB">
<property name="driverClassName">org.postgresql.Driver</property>
<property name="url">jdbc:postgresql://localhost:5432/mySchool</property>
<property name="username">admin</property>
<property name="password">admin</property>
</config>
<query id="GetStudentRecordNo" useConfig="mySchoolDB">
<sql>SELECT getstudentid FROM getstudentid(?)</sql>
<result outputType="json">{"entries": {"entry": [ { "getstudentid": "$getstudentid"} ]}}</result>
<param defaultValue="TEST" name="user_id" sqlType="STRING"/>
</query>
<operation name="getsrno">
<call-query href="GetStudentRecordNo">
<with-param name="user_id" query-param="user_id"/>
</call-query>
</operation>
<resource method="GET" path="getsrno">
<call-query href="GetStudentRecordNo">
<with-param name="user_id" query-param="user_id"/>
</call-query>
</resource>
</data>
You have to append the resource path ("getsrno" in your case) to the URL. Then the URL would look like,
http://LAPTOP-T4F1HOAM:8280/services/getStudRecNo/getsrno?user_id=test8
Further, since the resource's HTTP method is GET, the request should also be a GET request.

Why isn't this code writing log output on my Tridion Content Delivery server?

I have a user control rendering content from a custom (non-Tridion) database. The connection string for this custom database is incorrect, and so I'm getting an SqlException when the code tries to connect.
My code is currently:
var logger =
Tridion.ContentDelivery.Web.Utilities
.LoggerFactory.GetLogger(this.GetType().ToString());
try
{
/* make a database connection - failing with SqlException */
}
catch (SqlException e)
{
logger.Error("Could not connect to database: " + e.ToString());
}
My \bin\config\logback.xml file contains:
<property name="log.pattern" value="%date %-5level %logger{0} - %message%n"/>
<property name="log.history" value="7"/>
<property name="log.folder" value="c:/tridion/log"/>
<property name="log.level" value="DEBUG"/>
...
<appender name="rollingCoreLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.folder}/cd_core.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>${log.history}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<prudent>true</prudent>
</appender>
...
<root level="warn">
<appender-ref ref="rollingCoreLog"/>
</root>
There's a stack of logs in C:\Tridion\log, but the most recently changed one was modified 20 minutes ago, and doesn't contain my log message text (I just did a search for "database" in notepad).
Why isn't my log output being sent to the log?
You have 2 options:
You define the root logging to "DEBUG" but this has the disadvantage that allows a huge amount of logging from all the third-party libraries that Tridion is using. Here is the snippet: <root level="DEBUG"> <appender-ref ref="rollingCoreLog"/> </root>
You define a special appender to include also the Tridion .NET logging: <logger name="Tridion.ContentDelivery" level="${log.level}"><appender-ref ref="rollingCoreLog"/></logger>
Note that in the second case you need your logger to be bound to a namespace under Tridion.ContentDelivery. Here is an example:
var logger =
Tridion.ContentDelivery.Web.Utilities.LoggerFactory.GetLogger("Tridion.ContentDelivery.MyNamespace.MyClass");
Hope this helps.
P.S.: to answer your question: because you do not have an appender for it and the root logging is set to WARN. By default, the logback.xml contains appenders only for "com.tridion" but I guess that the output of this.getType().ToString() does not start with that string.

Spring MVC JDBC DataSourceTransactionManager: Data committed even after readonly=true

I am currently developing a Spring MVC application.I have configured a JDBC TransactionManager and I am doing declarative transaction management using AOP XML.However, even if I configure the method to run on a read-only=true, it still commits the transaction.
Database : Oracle 10g
My database-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schem...ring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
<property name="defaultAutoCommit" value="false" />
</bean>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath:com/mybatis/mappers/*.xml" />
</bean>
<!--
the transactional advice (what 'happens'; see the <aop:advisor/> bean
below)
-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true" />
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*" read-only="true" rollback-for="RuntimeException"/>
</tx:attributes>
</tx:advice>
<!--
ensure that the above transactional advice runs for any execution of
an operation defined by the FooService interface
-->
<aop:config>
<aop:pointcut id="fooServiceOperation"
expression="execution(* com.service.EmployeeService.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation" />
</aop:config>
</beans>
My controller
package com.service;
import java.util.List;
import com.mybatis.dao.EmployeeMapperInterface;
import com.spring.model.Employee;
public class EmployeeService implements EmployeeBaseService{
EmployeeMapperInterface employeeMapper;
public EmployeeMapperInterface getEmployeeMapper() {
return employeeMapper;
}
public void setEmployeeMapper(EmployeeMapperInterface employeeMapper) {
this.employeeMapper = employeeMapper;
}
#Override
public Employee getEmployeeById(long empId){
//retrieve from database
List empList = employeeMapper.getEmployeeWithId(empId);
if(empList != null && empList.size()>0){
return (Employee) empList.get(0);
}
return null;
}
#Override
public long saveEmployee(Employee employee){
long empId = 0l;
if(employee.getEmpId()==0){
empId = new Long( employeeMapper.insertEmployee(employee));
}else{
employeeMapper.updateEmployee(employee);
empId = employee.getEmpId();
}
try {
System.out.println("gonna sleep");
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
return empId;
}
How do I prevent the auto commit?I have also noticed that even if I don't put any transaction management code, the code still commits. Note, the transaction advice is however,invoked as when I put a no-rollback-for for RuntimeException and then do a 1/0, it correctly commits the data and rolls back if I put the same as rollback-for.
I have also tried out the query timeout by putting the thread on sleep, even that doesn't work, but I figure that timeout might be for an actual query, so thats fine.
Thanks in advance!
The advice read-only is only advice. It is not a requirement that the underlying transaction management system prevent writes when something is marked read-only, it is meant more as an optimization hint, saying that this method is read only, so you don't need to worry about it changing things. Some transaction managers will complain if changes are made in a read-only transaction, some will not. Generally, datasources acquired via JNDI will not. In any case, you should not rely on read-only advice preventing changes from being written back to disk.
Your options for preventing changes from being persisted are:
Mark the transaction rollback only or throw an exception having the same effect
Detach/evict the object from the transaction session before you change it
Clone the object and use the clone
DataSourceTransactionManager begins transaction with doBegin method.
From this method DataSourceUtils.prepareConnectionForTransaction called.
Inside this method you can see following code block:
if (definition != null && definition.isReadOnly()) {
try {
if (logger.isDebugEnabled()) {
logger.debug("Setting JDBC Connection [" + con + "] read-only");
}
con.setReadOnly(true);
}
catch (SQLException ex) {
So you could configure your logging framework to set log-level to DEBUG for DataSourceUtils class.
Or you could set breakpoint in this place and debug manually.
According to this article I expect that SET TRANSACTION READ ONLY will be executed on your Oracle connection.
And from Oracle docs we could see benefits which you receive in case of success:
By default, the consistency model for Oracle guarantees statement-level read consistency, but does not guarantee transaction-level read consistency (repeatable reads). If you want transaction-level read consistency, and if your transaction does not require updates, then you can specify a read-only transaction. After indicating that your transaction is read-only, you can execute as many queries as you like against any database table, knowing that the results of each query in the read-only transaction are consistent with respect to a single point in time.
The read-only behaviour is strictly driver specific. Oracle driver ignores this flag entirely. For instance the same update statements executed in Oracle will modify the database if run in read-only transaction, while in HSQL2 I was getting db level exceptions.
I know no other way than explicit rollback through api or exception to prevent commit in Oracle. Also this way your code will be portable between different drivers and databases.
The answer is on Spring MVC Mybatis transaction commit
Detailed stack traces are also available.
To summarize,
Read-only is only an advice and it guarantees nothing, and I would
really like the Spring docs to be updated about this.
whenever a query is executed in Oracle using Mybatis, it is in the context of a transaction which is automatically started,
committed(or rolled back, if execption is raised),and closed by
Mybatis.
Logging the application was a good idea and it helped me to find out how the actual transactions are started etc
.

Unauthorized error in Plone test, though content type can be added through the web

I've got a content type based on ATFolder:
ConceptSheetFolderSchema = folder.ATFolderSchema.copy()
ConceptSheetFolderSchema['title'].widget.label = _(u"Title")
ConceptSheetFolderSchema['title'].widget.description = _(u"")
ConceptSheetFolderSchema['title'].storage = atapi.AnnotationStorage()
ConceptSheetFolderSchema['description'].widget.label = _(u"Description")
ConceptSheetFolderSchema['description'].widget.description = _("")
ConceptSheetFolderSchema['description'].storage = atapi.AnnotationStorage()
finalizeATCTSchema(ConceptSheetFolderSchema, folderish=True, moveDiscussion=False)
class ConceptSheetFolder(folder.ATFolder):
"""
This is the central container for concept sheets in the site
"""
implements(IConceptSheetFolder)
portal_type = "Concept Sheet Folder"
_at_rename_after_creation = True
schema = ConceptSheetFolderSchema
title = atapi.ATFieldProperty('title')
description = atapi.ATFieldProperty('description')
atapi.registerType(ConceptSheetFolder, PROJECTNAME)
I can add a ConceptSheetFolder no problem through the Plone interface, but I can't get this basic test to work:
class TestContent(unittest.TestCase):
layer = PROJECT_CONCEPTSHEETS_INTEGRATION_TESTING
def test_hierarchy(self):
portal = self.layer['portal']
# Ensure that we can create the various content types without error
setRoles(portal, TEST_USER_ID, ('Manager',))
portal.invokeFactory('Concept Sheet Folder', 'csf1', title=u"Concept Sheet folder")
portal['csf1'].invokeFactory('project.ConceptSheet', 'cs1', title=u"ConceptSheet")
portal['csf1']['cs1'].invokeFactory('project.ConceptMilestone', 'cs1', title=u"Approved")`
I get a error
Unauthorized: Cannot create Concept Sheet Folder when I try this test. I Googled around a bit and found this Nabble post, leading me to look at isConstructionAllowed() in Plone/CMFCore/TestTools.py. Using pdb, I found that ._queryFactoryMethod(), when run in this context, is returning 'None'.
So it appears the FactoryTool for this type isn't working, at least not in the test. I've got the test in the normal GenericSetup place (types.xml, Concept_Sheet_Folder.xml, factorytool.xml), and I'm at a lost as to what else could be causing this problem. Any ideas?
Bonus question: why does this work in the Plone interface but not in the test?
Edit (Dec 13, 2011): Here's my Concept_Sheet_Folder.xml
<?xml version="1.0"?>
<object name="Concept Sheet Folder"
meta_type="Factory-based Type Information with dynamic views"
i18n:domain="iedea.conceptsheets" xmlns:i18n="http://xml.zope.org/namespaces/i18n">
<property name="title" i18n:translate="">Concept Sheet Folder</property>
<property name="description"
i18n:translate="">A folder which can contain concept sheets.</property>
<property name="content_icon">++resource++conceptsheetfolder_icon.gif</property>
<property name="content_meta_type">Concept Sheet Folder</property>
<property name="product">iedea.conceptsheets</property>
<property name="factory">addConceptSheetFolder</property>
<property name="immediate_view">atct_edit</property>
<property name="global_allow">True</property>
<property name="filter_content_types">True</property>
<property name="allowed_content_types">
<element value="Concept Sheet" />
</property>
<property name="allow_discussion">False</property>
<property name="default_view">view</property>
<property name="view_methods">
<element value="view"/>
</property>
<alias from="(Default)" to="(dynamic view)"/>
<alias from="edit" to="atct_edit"/>
<alias from="sharing" to="##sharing"/>
<alias from="view" to="(selected layout)"/>
<action title="View" action_id="view" category="object" condition_expr=""
url_expr="string:${folder_url}/" visible="True">
<permission value="View"/>
</action>
<action title="Edit" action_id="edit" category="object" condition_expr=""
url_expr="string:${object_url}/edit" visible="True">
<permission value="Modify portal content"/>
</action>
</object>
I've run into this problem myself. The problem is that the your Archetype's factory is not yet properly registered by the time you are trying to create it.
That's why _queryFactoryMethod() returns None, as you found out.
The solution differs a bit on whether you are using Products.ZopeTestCase or the newer plone.app.testing as your testing framework.
However, in both cases you need to make sure that the add-on product that defines the Archetype (ConceptSheetFolder) that you are trying to create (via invokeFactory), has aready been installed.
When using Products.ZopeTestCase:
In the case that you are using Products.ZopeTestCase (and Products.PloneTestCase), you need to call
Products.ZopeTestCase.installProduct
You need to make sure that your installProduct call does not get deferred until after your test is called.
In Plone 4 this means that your installProduct call should not be in an #onsetup decorated function (although this will still work in Plone 3).
This mailing list discussion might further clear things up:
http://plone.293351.n2.nabble.com/invokeFactory-failing-on-Plone-4-PTC-but-working-on-Plone-3-td5755482.html
When using plone.app.testing:
If you are using plone.app.testing, you should call:
plone.testing.z2.installProduct
This should be done in the setUpZope method that you override from the PloneSandboxLayer.
For more info, read the description under setUpZope in plone.app.testing.helpers.py (Line 257)
https://github.com/plone/plone.app.testing/blob/2ef789f8173c695179b043fd4634e0bdb6567511/plone/app/testing/helpers.py

Resources