testrail-python icon indicating copy to clipboard operation
testrail-python copied to clipboard

Config collision when creating multiple client instances

Open lbjay opened this issue 7 years ago • 7 comments

It is not possible to create multiple client instances to different testrail accounts within a single session. A brief glance at the code in api.py suggests it's probably related to config settings being stored in API class attributes.

In [1]: from testrail import TestRail

In [2]: tr1 = TestRail(project_id=1, email='[email protected]', key='abc123', url='https://foo.testrail.net')

In [3]: tr2 = TestRail(project_id=1, email='[email protected]', key='xyz999', url='https://bar.testrail.net')

In [4]: tr2.api._config
Out[4]: 
{'email': '[email protected]',
 'key': 'xyz999',
 'url': 'https://bar.testrail.net'}

In [5]: tr1.api._config
Out[5]: 
{'email': '[email protected]',
 'key': 'xyz999',
 'url': 'https://bar.testrail.net'}

lbjay avatar Mar 13 '17 19:03 lbjay

I thought there was a reason it was done this way but I can't recall what it was. That being said you have a very valid use case. I will look into it tonight.

travispavek avatar Mar 13 '17 20:03 travispavek

They were stored as class attributes because of the way the API class is instantiated in multiple places throughout the code.

leviable avatar Mar 13 '17 20:03 leviable

Yeah this is going to be a bigger issue than I thought. The way we store our cache in shared state will clobber multiple instances as well.

travispavek avatar Mar 13 '17 20:03 travispavek

Yeah, so we make very heavy use of the fact that that API class using the borg pattern. So multiple instances will not work without a fairly heavy refactor. PRs are welcome but this is not something that I will plan to do unless it becomes a major issue.

@lbjay is this a showstopper for you? What are you trying to accomplish? Maybe we can find a different way to achieve it.

travispavek avatar Mar 13 '17 21:03 travispavek

After digging around in the code for a bit, I concur with Travis: it would take a non-trivial refactoring of the code to make your example work.

One thing I just noticed while debugging something: the changes to API to store the credentials in the a class attribute are in the master branch, but haven't been officially released to PyPI yet. This may or not be affecting @lbjay, depending on if he is using the tip of master, or the 3.7 on PyPI.

leviable avatar Mar 14 '17 15:03 leviable

I pushed master to 0.3.8 on PyPI. While a major hack, and slower it may work to set api._timeout to 0. The two instances will constantly clobber each other but being the cache will always be marked as stale it wouldn't matter. This assumes of course that the processes are not running in parallel.

travispavek avatar Mar 14 '17 17:03 travispavek

I've been looking at this off and on all day. For future reference, there are two options that I can see to make multiple clients work within the same python process:

  1. Create a client id with each testrail client, and use a combination performing object introspection on the calling object and overriding the __new__ constructor of TestRaileBase to propagate the client id throughout the system. This would require the least amount of code change, but breaks encapsulation. Additionally, the introspection method involves using python's inspect module to inspect the previous frame, and this is frowned upon by the python community for anything but debugging.

  2. Create a client id with each testrail client, and explicitly propagate that through the system by including it with every testrail object instantiation. The API would be modified to map client connection configurations and _shared_state objects to the client ids. This would be the cleanest approach, but would touch a significant portion of the code base.

In either case, I'm not sure its possible to make multiple client instances work AND keep the borg design pattern of API intact.

leviable avatar Mar 14 '17 19:03 leviable