Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Helper for conditional percent statements #239

Closed
ppcano opened this issue Jun 7, 2017 · 5 comments
Closed

Helper for conditional percent statements #239

ppcano opened this issue Jun 7, 2017 · 5 comments
Assignees
Milestone

Comments

@ppcano
Copy link
Contributor

ppcano commented Jun 7, 2017

We discussed in the Slack channel the case of executing some flow only for a specific percent of the current execution users.

These gists provide some use cases:

https://gist.github.com/ppcano/14d66b7b3ec6993ed63eaed8f2ebecae
https://gist.github.com/ppcano/ed545a322c1ed4b6ee61f0fe34ac6694

A helper to manage this case may be useful. Below an example to illustrate the case (not a syntax proposal):

import {randomSwitch} from 'k6';


randomSwitch( () =>{
  this.case('25',() => {

  });
  this.case('50', () => {

  });
  this.case('25', () => {

  });
});

@liclac
Copy link
Contributor

liclac commented Jun 9, 2017

After thinking about it, I feel like a modulo on the VU ID (__VU % 10 == 1, etc. for every 10th VU) may be the best way to do this. It won't give you precise control in all cases, but I'm not sure there is a much cleaner method than that.

You could do something rather overblown where some VUs get certain variables assigned, but honestly, it'd accomplish the exact same thing.

@na--
Copy link
Member

na-- commented Jul 2, 2019

This proposal will mostly be covered by the changes in #1007

@na-- na-- added this to the v0.27.0 milestone May 21, 2020
@na-- na-- self-assigned this May 21, 2020
@na--
Copy link
Member

na-- commented Jul 6, 2020

Closing this, since the just-merged #1007 implements native support for multi-scenario tests, just in another way

@na-- na-- closed this as completed Jul 6, 2020
@schrufygroovy
Copy link

schrufygroovy commented Dec 3, 2020

@na--
Can you please explain to me, how #1007 is covering this?

randomSwitch( () =>{
  this.case('0.132',() => {

  });
  this.case('0.423', () => {

  });
  this.case('1.924', () => {

  });
  this.case('21.83', () => {

  });
  // and so on for > 50 scenarios
});

with let's say only 2 VUs (or scaling up or ramping up number of VUs) and an nonfixed number of total requests? Or is this ones of the things that isn't covered (as you wrote will mostly be covered)?

@na--
Copy link
Member

na-- commented Dec 4, 2020

As I explained in the community forum, VUs can't be shared between scenarios. But in a single scenario, you can easily implement a random weighted distribution of its iteration. Posting the same example implementation of a "randomSwitch" function here as well, in case someone stumbles on this issue and not the forum thread:

import { sleep } from 'k6';

function weightedSwitch(weightedFuncs) {
    var funcIntervals = new Array(weightedFuncs.length)

    var weightSum = 0;
    for (var i = 0; i < weightedFuncs.length; i++) {
        funcIntervals[i] = {
            start: weightSum,
            end: weightSum + weightedFuncs[i][0],
            func: weightedFuncs[i][1],
        }
        weightSum += weightedFuncs[i][0];
    }

    if (Math.abs(weightSum - 1) > 0.0001) {
        throw new Error('the sum of function weights should be 1 (100%), but is ' + weightSum);
    }

    return function (val) {
        var guess, min = 0, max = funcIntervals.length - 1;;
        while (min <= max) {
            guess = Math.floor((max + min) / 2);

            if (val >= funcIntervals[guess].end) {
                min = guess + 1;
            } else if (val < funcIntervals[guess].start) {
                max = guess - 1;
            } else {
                return funcIntervals[guess].func;
            }
        }
    }
}

export let options = {
    duration: '1m',
    vus: 2,
};

var getFunction = weightedSwitch([
    [0.1, () => "scenario 0 (10%)"],
    [0.1, () => "scenario 1 (10%)"],
    [0.21, () => "scenario 2 (21%)"],
    [0.39, () => "scenario 3 (39%)"],
    [0.199, () => "scenario 4 (19.9%)"],
    [0.001, () => "scenario 5 (0.1%)"],
])


export default function () {
    var rand = Math.random();
    var f = getFunction(rand);
    console.log(`VU ${__VU}, iter ${__ITER}, rand ${rand.toFixed(4)} executed ${f()}`);
    sleep(1);
}

I don’t make any guarantees that I don’t have an off-by-one error in the binary search code or something like that, I haven’t tested this code much, but it seems to work well enough… Running it should result in something like this:

INFO[0000] VU 2, iter 0, rand 0.3661 executed scenario 2 (21%)  source=console
INFO[0000] VU 1, iter 0, rand 0.4241 executed scenario 3 (39%)  source=console
INFO[0001] VU 2, iter 1, rand 0.3712 executed scenario 2 (21%)  source=console
INFO[0001] VU 1, iter 1, rand 0.1931 executed scenario 1 (10%)  source=console
INFO[0002] VU 1, iter 2, rand 0.3077 executed scenario 2 (21%)  source=console
INFO[0002] VU 2, iter 2, rand 0.7144 executed scenario 3 (39%)  source=console
INFO[0003] VU 1, iter 3, rand 0.6757 executed scenario 3 (39%)  source=console
INFO[0003] VU 2, iter 3, rand 0.1091 executed scenario 1 (10%)  source=console
INFO[0004] VU 1, iter 4, rand 0.9282 executed scenario 4 (19.9%)  source=console
INFO[0004] VU 2, iter 4, rand 0.5826 executed scenario 3 (39%)  source=console
...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants