Headless browser and locust.io - locust

Is it possible to integrate a headless browser with locust? I need my load tests to process client side script that triggers additional requests on each page load.

That's an old question, but I came across it now, and found a solution in "realbrowserlocusts" (https://github.com/nickboucart/realbrowserlocusts) - it adds "Real Browser support for Locust.io load testing" using selenium.
If you use one of its classes (FirefoxLocust, ChromeLocust, PhantomJSLocust) instead of HttpLocust for your locust user class
class WebsiteUser(HeadlessChromeLocust):
then in your TaskSet self.client becomes an instance of selenium WebDriver.
One drawback for me was that webdriver (unlike built-in client in HttpLocust) doesn't know about "host", which forces to use absolute URLs in TaskSet instead of relative ones, and it's really convenient to use relative URLs when working with different environments (local, dev, staging, prod, etc.).
But there is an easy fix for this: to inherit from one of realbrowserlocusts' locusts and pass "host" to WebDriver instance:
from locust import TaskSet, task, between
from realbrowserlocusts import HeadlessChromeLocust
class UserBehaviour(TaskSet):
#task(1)
def some_action(self):
# self.client is selenium WebDriver instance
self.client.get(self.client.base_host + "/relative/url")
# and then for inst. using selenium methods:
self.client.find_element_by_name("form-name").send_keys("your text")
# etc.
class ChromeLocustWithHost(HeadlessChromeLocust):
def __init__(self):
super(ChromeLocustWithHost, self).__init__()
self.client.base_host = self.host
class WebsiteUser(ChromeLocustWithHost):
screen_width = 1200
screen_height = 1200
task_set = UserBehaviour
wait_time = between(5, 9)
============
UPDATE from September 5, 2020:
I posted this solution in March 2020, when locust was on major version 0. Since then, in May 2020, they released version 1.0.0 in which some backward incompatible changes were made (one of which - renaming StopLocust to StopUser). realbrowserlocusts was not updated for a while, and is not updated yet to work with locust >=1.
There is a workaround though. When locust v1.0.0 was release, previous versions were released under a new name - locustio with the last version 0.14.6, so if you install "locustio==0.14.6" (or "locustio<1"), then a solution with realbrowserlocusts still works (I checked just now). (see https://github.com/nickboucart/realbrowserlocusts/issues/13).
You have to limit a version of locustio, as it refuses to install without it:
pip install locustio
...
ERROR: Command errored out with exit status 1:
...
**** Locust package has moved from 'locustio' to 'locust'.
Please update your reference
(or pin your version to 0.14.6 if you dont want to update to 1.0)

In theory you could make a headless browser a Locust slave/worker. But the problem is that the browser is much more expensive in terms of CPU and memory which would make it difficult to scale.
That is why Locust uses small greenlets to simulate users since they much cheaper to construct and run.
I would recommend you to break down your page's requests and encode them as requests inside of Locust. The Network tab in Chrome's Dev Tools is probably a good start. I've also heard of people capturing these by going through a proxy that logs all requests for you.

You could use something like browserless to take care of the hosting of Chrome (https://browserless.io). Depending on how you brutal your load tests are there’s varying degrees of concurrency. Full disclaimer: I’m the maker of the browserless service

I think locust is not desinged for that purposes, it is for creating concurrent user to make http requests so I didnt see any integration with locust and browser. However you can simulate browser by sending extra information in the header with that way client side scripts will also work.
r = self.client.get("/orders", headers = {"Cookie": self.get_user_cookie(user[0]), 'User-Agent': self.user_agent})

The locust way of solving this is to add more requests to your test that mimic the requests that the javascript code will make.
I structure my locust tests to parse the JSON response from an early request in the app's workflow. I then randomly pick some interesting piece of data from that JSON, and then issue more requests that mimic what would happen in the browser if the user had clicked on that piece of data.

Related

When to build routes and API spec with TSOA

I am trying to implement TSOA with an existing HapiJS server and would like some insight on the best approach.
You can run tsoa spec-and-routes to generate routes.ts and swagger.json. However, running this manually before running the node process is less than ideal.
The solution would be then to run them programatically using the APIs provided by the TSOA library. However, when registering the routes with my Hapi server, I need to import the generated routes.ts file. e.g import RegisterRoutes from '../build/routes.ts.
So when I run the node process, generate the routes during this (programatically), it tries to grab '../build/routes.ts' before it has been built. Producing an error and the node proceess exits.
What is the way around this?
tsoa spec-and-routes && node bin/node ?
Any clarification would be greatly appreciated. Thanks.

GitLab health endpoint before integrating code

I’m new to deploying ML models and I want to deploy a model that contains several modules, each of which consist of “folders” containing some data files, .py scripts and a Python notebook.
I created a project in GitLab and I’m trying to follow tutorials on FastAPI since this is what I’m gonna be using. But I’ve been told that before I start integrating the code, I need to set up a health endpoint.
I know about the request curl "https://gitlab.example.com/-/health", but do I need to set up anything? Is there anything else I need to do for the project setup before doing the requirements.txt, building the skeleton of the application etc.?
It depend totaly of your needs, there is no health endpoint implemented natively in fastapi.
But I’ve been told that before I start integrating the code, I need to set up a health endpoint.
not necessarly a bad practice, you could start by listing all your futur health checks and build your route from there.
update from comment:
But I don’t know how to implement this. I need a config file? I’m very new to this.
From what i understand you are very new to python api so you should start by following the official fastapi user guide. You can also follow fastapi first steps from this.
Very basic one file project that run as is:
# main.py
from fastapi import FastAPI
app = FastAPI()
#app.get("/health")
async def root():
return {"message": "Alive!"}
Remember that the above is not suitable for production, only for testing/learning purposes, to make a production api you should follow the official advanced user guide and implement something like the following.
more advanced router:
You have this health lib for fastapi that is nice.
You can make basic checks like this:
# app.routers.health.py
from fastapi import APIRouter, status, Depends
from fastapi_health import health
from app.internal.health import healthy_condition, sick_condition
router = APIRouter(
tags=["healthcheck"],
responses={404: {"description": "not found"}},
)
#router.get('/health', status_code=status.HTTP_200_OK)
def perform_api_healthcheck(health_endpoint=Depends(health([healthy_condition, sick_condition]))):
return health_endpoint
# app.internal.health.py
def healthy_condition(): # just for testing puposes
return {"database": "online"}
def sick_condition(): # just for testing puposes
return True

Can I call synchroniseUserDirectories (ConfluenceRpc) via REST, SOAP or XML-RPC?

I am using Confluence 4.2.5 (build 3284) with CAS SSO connected to my LDAP server and would like to be able to call synchroniseUserDirectories() from the LDAP server when a user changes their password so that the change is instantaneous.
The way it works now is that users have to wait for the Confluence to run it's periodic LDAP synchronization which can be disconcerting for them.
I have tried using the XML-RPC interface to call changeUserPassword() (as an administrator) but it doesn't work. The operation raises an exception "Error changing password for user ...". I presume that that is because the user is defined in the LDAP but I can't tell for sure because the exception message wasn't clear about the cause.
Here is example code that I would like to be able to use. It doesn't work.
#!/usr/bin/env python
import xmlrpclib
url = 'https://docs.example.com'
admin_user = 'frobisher'
admin_pass = 'supersecretstuff'
username = 'bigbob'
new_password = 'bigbobsbigsecret'
server = xmlrpclib.ServerProxy(url + '/rpc/xmlrpc')
token = server.confluence2.login(admin_user, admin_pass)
# CITATION: https://developer.atlassian.com/display/CONFDEV/Remote+Confluence+Methods
# this doesn't exist but would be my preferred approach.
# It raises a NoSuchMethodException exception.
server.confluence2.synchroniseUserDirectories(token)
# this throws a general exception, because of the LDAP? The message
# wasn't clear about the source of the problem.
#server.confluence2.changeUserPassword(token,
# username,
# password)
server.confluence2.logout(token)
Is there any way to do this using SOAP or REST? I was concerned about REST because it sounds like it is still a prototype.
If none of those approaches will work, can it be done with a simple plugin considering that this must be a push operation from the LDAP server to the Confluence server? I have no experience writing plugins but I do some java work occasionally.
Any hints would be greatly appreciated.
The short answer is "no". The ability to synchronise remote user directories is not exposed as a remote operation in Confluence.
The long answer is "yes", you can write a plugin to do this. If you're already familiar with java, then perhaps the best answer is to just show you some source code I've written that performs a similar function: https://bitbucket.org/jaysee00/confluence-user-sync-api This plugin gives you SOAP, XML-RPC and JSON-RPC methods to force an individual user account to be synced in to Confluence from a remote directory.
That might suit your purposes as-is, but I imagine it would be possible to edit the source of this plugin and change it to synchronise an entire directory, too.

Why is Rails caching assets in development mode on my iPhone?

According to the Ruby on Rails Guide: Caching, caching is disabled by default in the development and testing environments. If I make a small CSS change, run rails server and access my site at localhost:3000, I can see my change. However, if I access my rails server on my iPhone at 10.0.1.2:3000, the CSS doesn't update, even Chrome in Incognito Mode. When I try different iPhone that has an empty cache, the change is there.
I found a stack overflow post that described the same problem. Here were the suggested solutions:
Remove the public/assets directory. I don't have one.
Add config.serve_static_assets = false to environments/development.rb. It's already there.
Delete /tmp/cache/assets, add config.serve_static_assets = false to environments/development.rb and restart the server. I tried this and it didn't work.
Here's my relevant environments/development.rb config:
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false
# Show full error reports and disable caching
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
I'm pretty sure this is happening because Rails only does fingerprinting in production: http://guides.rubyonrails.org/asset_pipeline.html#in-production
This means that in development browsers that are more cache-aggressive can run into this issue.
Try adding this to your development.rb:
config.assets.digest = true
Or more preferable something conditional for when you're doing mobile development
# One of the few exceptions I'd make to a no ENV variables rule
# for my rails environment config files
config.assets.digest = true if ENV["MOBILE_DEBUG"]
How are use accessing your local machine via your iphone ?
have you configured any network settings or you push it to a different server and access from there, because the thing is if you are pusing it to a different server , that sever might be running in the production mode.
HTH
I don't have an iPhone to test, but it sounds like a normal browser caching issue. Try these instructions for clearing the browser cache. If that works, you'll need to do it each time you update your CSS (or J
I had a similar problem. It happened because my config/environments/development.rb had contained config.asset_host = 'http://localhost:3000'
I've removed it and all works fine.

Sending events to the dev version of a ruleset via HTTP

I've been writing an endpoint that sends events to a KRL ruleset via HTTP GET (based on the documentation here), in this format:
http://cs.kobj.net/blue/event/{domain}/{eventname}/{appid}
That works great when the version of the app I want to test is the same one that's deployed. I don't always want to deploy before testing it, though. Using the stated format for calling the dev version doesn't work. It still calls the deployed version of my ruleset:
http://cs.kobj.net/blue/event/{domain}/{eventname}/{appid}:kynetx_app_version=dev
What am I doing wrong?
{appid}:kynetx_app_version=dev
is a query parameter so it needs to come after a '?' or a '&'
Changing your query to the following should get it to work
http://cs.kobj.net/blue/event/{domain}/{eventname}/{appid}/?{appid}:kynetx_app_version=dev