I'm studying the execution of performance tests using K6.
Doing the Postman login test scenario, the result was positive:
Running the test with Postman
I exported the Postman collection and did the file conversion for K6 to recognize it.
Then, when running the test through K6, the following is returned:
Running the test with K6
This detail caught my attention:
✗ Successful POST request
↳ 0% — ✓ 0 / ✗ 1
Am I doing something wrong?
Thanks!
Edit: This is the print with the complete result after running the test.
Result
Edit 2: I'm putting the generated script that is being executed by K6, hiding only the address and login information:
// Auto-generated by the postman-to-k6 converter
import "./libs/shim/core.js";
import "./libs/shim/expect.js";
export let options = { maxRedirects: 4 };
const Request = Symbol.for("request");
postman[Symbol.for("initial")]({
options
});
export default function() {
postman[Request]({
name: "New Request",
id: "2140438e-8869-4836-ae80-7c5845d09572",
method: "POST",
address: "https://xxxx-xxxxxxx.xxxxxxx.xxx/public/auth/signin",
data: '{\r\n "username": "xxxxxxxxxxx",\r\n "password": "xxxxxx"\r\n}',
post(response) {
pm.test("Successful POST request", function() {
pm.expect(pm.response.code).to.be.oneOf([201, 202]);
});
}
});
}
Related
for example, how to log out debug info Hello world for
import * as log from "https://deno.land/std#0.173.0/log/mod.ts";
// Simple default logger out of the box. You can customize it
// by overriding logger and handler named "default", or providing
// additional logger configurations. You can log any data type.
log.debug("Hello world");
log.info(123456);
log.warning(true);
log.error({ foo: "bar", fizz: "bazz" });
log.critical("500 Internal server error");
from https://deno.land/std#0.173.0/log/mod.ts
I tried deno run -A --log-level=DEBUG with no luck.
for example, how to log out debug info Hello world for...
Below is an example of how you can configure all levels of logging to the console at "DEBUG" and above.
The module at https://deno.land/std#0.174.0/log/mod.ts includes some example code that looks just like the lines in your question (on lines 97-153 in the file) — it is what I used as a basis for the code below.
so-75244033.ts:
import * as log from "https://deno.land/std#0.174.0/log/mod.ts";
// This could be read from an environment variable or parsed from a CLI argument:
const LOG_LEVEL = "DEBUG";
log.setup({
handlers: {
console: new log.handlers.ConsoleHandler(LOG_LEVEL),
},
loggers: {
default: {
level: LOG_LEVEL,
handlers: ["console"],
},
},
});
// Simple default logger out of the box. You can customize it
// by overriding logger and handler named "default", or providing
// additional logger configurations. You can log any data type.
log.debug("Hello world");
log.info(123456);
log.warning(true);
log.error({ foo: "bar", fizz: "bazz" });
log.critical("500 Internal server error");
In the terminal:
% deno --version
deno 1.30.0 (release, x86_64-apple-darwin)
v8 10.9.194.5
typescript 4.9.4
% deno run so-75244033.ts
DEBUG Hello world
INFO 123456
WARNING true
ERROR {"foo":"bar","fizz":"bazz"}
CRITICAL 500 Internal server error
My question is, how can I delete a users analytics data from firebase using "Google User Deletion API" and its method: userdeletionRequests:upsert? This is important for me to fully fulfill GDPR.
I tried searching for this, but didn't a solution for using it in combination with "NodeJS" and "firebase-cloud-functions".
My biggest problem is, how I get the access, token, this is what I have for now:
const accessToken = (await admin.credential.applicationDefault().getAccessToken()).access_token;
return ky.post(constants.googleUserDeletionURL, {
body: JSON.stringify({
kind: "analytics#userDeletionRequest",
id: {
type: "USER_ID",
userId: uid,
},
propertyId: constants.googleUserDeletionPropertyId,
}),
headers: {
"Authorization": `Bearer ${accessToken}`,
},
}).catch((err) => {
functions.logger.log(`An Error happened trying to delete user-anayltics ${(err as Error).message}`);
});
But I always get An Error happened trying to delete user-anayltics Request failed with status code 403 Forbidden
Okay, after some painful and long days (literally took me like >20 hours), I've figured out how to achieve this request. Here is a step for step guide:
Step 1 - Needed Dependencies
To send a post-request to google, we need a http-client-library. I've choosen "ky", so we need to install it first with:
npm install ky
Furthermore, we need to create or OWN oAuth2 token, otherwise the post request will be denied with "error 403". To create our own oAuth token, we need another dependency:
npm install #googleapis/docs
Step 2 - Needed Google Property ID
With your request, Google needs to know which property-id / project you are targeting (where it should later delete the user-analytics-data). To get this property-id, we need to log in into GCP via Firebase (not the "real" GCP, the one via Firebase).
For this, go into your "console.firebase.google.com" → Select your project → Analytics Dashboard → "View more in Google Analytics (button at the right corner)"
Write "property-id" into the search field and then save it somewhere (we need it later)
Step 3 - Creating Client-Secret
The third step is to create a service-account, which we will later add into our functions-folder, in order to create our oAuthClient (don't worry, you will see what I mean to a later point)
To create your new service.json, log in to google cloud platform via "https://cloud.google.com/" and then follow the pictures:
FIRST:
SECOND:
THIRD:
FOURTH:
FIFTH
Step 4 - Download JSON
After we created our "oAuth-Deleter service-account", we need to manually download the needed JSON, so we can paste it into our functions-folder.
For this, select "oauth-deleter#your-domain.iam.gserviceaccount.com" under "Service Account"
Then click on "Keys" and "Add key", which will automagically download you a service-json (SELECT Key type → JSON → Create).
Step 5 - Paste JSON file into your functions-folder
To loosen up the mood a bit, here is an easy step. Paste the downloaded JSON-File into your functions-folder.
Step 6 - Grant Access to our new created oAuth-Delelter-Account
Creating the service-account and giving it access in the normal GCP is not enough for Google, so we also have to give it access in our Firebase project. For this, go back into your "GCP via Firebase (see Step 2)" → Click on Setting → "User Access for Account" → Click on the "plus"
Then click on "Add user" and write the email we copied before into the email field (the email from Step 3, Picture FOURTH "Service-Account ID). In our case, it is "oAuth-Deleter#your-domain.iam.gserviceaccount.com". Furthermore, it needs admin-access:
Step 6 - The code
Now, after these million unnecessary but necessary steps, we get to the final part. THE DAMN CODE. I've written this in typescript with "compilerOptions" → "module": "esnext", "target": "esnext". But I am sure that you are smart enough to change the code after completing this many steps :)
import admin from "firebase-admin";
import functions from "firebase-functions";
import ky from "ky";
import docs from "#googleapis/docs";
import { UserRecord } from "firebase-functions/v1/auth";
export const dbUserOnDeleted = functions.
.auth
.user()
.onDelete((user) => doOnDeletedUser(user))
----------------------------
export asnc function doOnDeletedUser/user: UserRecord) {
try {
const googleDeletionURL = "https://www.googleapis.com/analytics/v3/userDeletion/userDeletionRequests:upsert"
// Step 1: Paste propertyID: (See Step 2)
const copiedPropertyID = "12345678"
// Step 2: Create oAuthClient
const oAuthClient = new docs.auth.GoogleAuth({
keyFile: "NAME-OF-THE-FILE-YOU-COPIED-INTO-YOUR-FUNCTIONS-FOLDER",
scopes: ["https://www.googleapis.com/auth/analytics.user.deletion"]
});
// Step 3: Get user uid you want to delete from user-analytics
const uid = user.uid
// Step 4: Generate access token
// (this is the reason why we needed the 5 steps before this)
// yup, a single line of code
const accessToken = await oAuthClient.getAccessToken() as string;
// Step 5: Make the request to google and delete the user
return ky.post(googleDeletionURL, {
body: JSON.stringify({
kind: "analytics#userDeletionRequest",
id: {
type: "USER_ID",
userid: uid
},
propertyId: copiedPropertyID
}),
headers: {
"Authorization": "Bearer " + accessToken,
}
});
} catch (err) {
functions.logger.error(`Something bad happened, ${(err as Error).message)`
}
}
Afterthoughts
This was and probably will be my longest post at stack overflow forever. I have to say that it was a pain in the a** to get this thing to working. The amount of work and setup that is needed to simply delete a data from one endpoint is just ridiculous. Google, please fix.
I am working with the prometheus pushgateway library and am having trouble sending information to it. The examples use cURL which work well, but when I try to do the equivalent with AXIOS in my node program it throws an error.
I tried setting up an express server to send the same request to. I wanted to analyze the (REQ) and see how it was displayed. It was mangled by body parser and I am kind of lost.
cat <<EOF | curl --data-binary #- http://pushgateway.example.org:9091/metrics/job/some_job/instance/some_instance
# TYPE some_metric counter
some_metric{label="val1"} 42
# TYPE another_metric gauge
# HELP another_metric Just an example.
another_metric 2398.283
EOF
I have tried a few different things in axios, none of which have worked
- https://github.com/axios/axios#using-applicationx-www-form-urlencoded-format
request({
url: 'http://localhost:9091/metrics/job/interface_data',
method: 'POST',
body: 'datahere 10\n',
encoding: null
}, (error, response, body) => {
if (error) {
console.log(error)
} else {
console.log(response)
console.log('response, ', response.body)
}
})
Worked for me. The trick was encoding: null
Problem Description
My Android app collects data via Google Analytics for Firebase. For privacy reasons, users must be able to wipe their data off the Firebase servers, should they choose to do so.
The app requests a deletion by forwarding its Firebase APP_INSTANCE_ID to my own server. This server has been prepared in advance with credentials, from my personal Google account (via oauth2), for managing the Firebase project. The server authenticates with www.googleapis.com, and, using the supplied APP_INSTANCE_ID, invokes the upsert.
As noted by the documentation, the generic Google Analytics API is appropriate for this task.
After some initial trouble (b/c I didn't have the correct auth scope, and the Analytics API wasn't properly enabled), googleapis.com now returns HTTP 200 for each upsert request. (As an aside, even if you supply a bogus APP_INSTANCE_ID, it returns 200.)
Here is a sample response from the upsert, which shows nothing amiss:
{ kind: 'analytics#userDeletionRequest',
id:
{ type: 'APP_INSTANCE_ID',
userId: (REDACTED 32-char hexidecimal string) },
firebaseProjectId: (REDACTED),
deletionRequestTime: '2018-08-28T12:46:30.874Z' }
I know the firebaseProjectId is correct, because if I alter it, I get an error. I have verified that the APP_INSTANCE_ID is correct, and stable up until the moment it is reset with resetAnalyticsData().
Test Procedure
To test the deletions, I populated Firebase with several custom events, using the procedure below (Nexus 5X emulator, no Google Play, no Google accounts configured, but that shouldn't make any difference):
Install the app
Fire off some custom events (FirebaseAnalytics.logEvent)
Observe those events appear on the Firebase console
(About a minute later:) Make the upsert call, observe HTTP 200, and note the "deletionRequestTime"
Immediately call FirebaseAnalytics.resetAnalyticsData (to clear any event data cached on the device)
Uninstall the app
Rinse & repeat 7 or 8 times
However, even 24 hours later, 100% of the Firebase events are still present in the events table. No discernable state change has taken place on the Firebase server as a result of the upserts.
Question
So, what am I doing wrong? how do I successfully delete user data from Google Analytics for Firebase?
EDIT
Here's the code I'm using to make a request (from node.js):
const request = require( 'request' );
...
_deletePersonalData( data )
{
return new Promise( (resolve, reject) => {
request.post({
url: 'https://www.googleapis.com/analytics/v3/userDeletion/userDeletionRequests:upsert',
body: {
kind: 'analytics#userDeletionRequest',
id: {
type: 'APP_INSTANCE_ID',
userId: data.firebaseAppInstanceId
},
firebaseProjectId: (REDACTED)
},
headers: {
Authorization: 'Bearer ' + iap.getCurAccessToken()
},
json: true
}, (err, res, body) => {
console.log( 'user-deletion POST complete' );
console.log( 'Error ' + err );
console.log( 'Body ', body );
if( err )
{
reject( err );
return;
}
if( body.error )
{
reject( new Error( 'The Google service returned an error: ' + body.error.message + ' (' + body.error.code + ')' ) );
return;
}
resolve({ deletionRequestTime: body.deletionRequestTime });
});
});
}
Here's a sample request body:
{
kind: 'analytics#userDeletionRequest',
id: {
type: 'APP_INSTANCE_ID',
userId: (REDACTED 32-char hexidecimal string)
},
firebaseProjectId: (REDACTED)
}
And here's the console output for that same request (same userId and everything):
user-deletion POST complete
Error: null
Body: { kind: 'analytics#userDeletionRequest',
id:
{ type: 'APP_INSTANCE_ID',
userId: (REDACTED 32-char hexidecimal string) },
firebaseProjectId: (REDACTED),
deletionRequestTime: '2018-08-29T17:32:06.949Z' }
Firebase support just got back to me, and I quote:
Upsert method deletes any individual user data we have logged, but aggregate metrics are not recomputed. This means that you might not see any changes in the events tab in your Analytics console.
So, basically my mistake was expecting the events to disappear from the console.
This, of course, raises the question of how one determines that the API is actually working... but maybe the HTTP 200 is enough.
Nearly every single example i've found on web isn't well explained how mocha should be implemented and used with nightwatchJS.
Whatever i do i am not able to avoid that error message, even if i follow all steps from official nightwatch how-to use mocha
Only thing that i was able to do is to at least make google chrome browser open and thats it.
Here is the code i am trying to run
var nightwatch = require('nightwatch');
describe('Google', function() {
var client = nightwatch.initClient({
// Pass here options from nightwatch.json
// selenium logs; change it to true if you want to see them in console
silent : false,
desiredCapabilities: {
browserName: "chrome",
javascriptEnabled: true,
acceptSslCerts: true
}
});
var browser = client.api();
// Mocha timeout
this.timeout(15000);
it('Demo test Google', function (done) {
browser
.url('http://www.google.com')
.waitForElementVisible('body', 1000)
.setValue('input[type=text]', 'nightwatch')
.waitForElementVisible('button[name=btnG]', 1000)
.click('button[name=btnG]')
.pause(1000)
.assert.containsText('#main', 'Night Watch')
.end();
client.start(done);
});
});
And this is the error message that always happen to me after the browser pop up:
INFO Request: POST /wd/hub/session
- data: {"desiredCapabilities":{"browserName":"firefox","javascriptEnabled":true,"acceptSslCerts":true,"platform":"ANY"}}
- headers: {"Content-Type":"application/json; charset=utf-8","Content-Length":113}
1) Demo test Google
0 passing (15s)
1 failing
1) Google Demo test Google:
Error: timeout of 15000ms exceeded. Ensure the done() callback is being called in this test.
The original question states that there is no great documentation regarding how to set up nightwatch with mocha. I discovered this to be the case myself this weekend as I looked to set up my nightwatch tests with mocha.
I was able to set up my nightwatch tests without seeing the done callback error by doing the following:
I used a nightwatch.conf.js but I believe you can also do the following in nightwatch.json:
module.exports = {
src_folders : ["test"],
test_runner: {
type: 'mocha',
options: {
ui: 'bdd',
reporter: 'spec'
}
},
...
}
Simple right?
This allows mocha to run your nightwatch tests.
Much simpler, friendlier syntax IMO.
Here are the relevant parts of my package.json:
{
"name": "nightwatch-mocha",
"directories": {
"test": "test"
},
"scripts": {
"nightwatch": "nightwatch -c ./nightwatch.conf.js"
},
"devDependencies": {
"chromedriver": "^73.0.0",
"mocha": "^6.1.4",
"nightwatch": "^1.0.19"
}
}
I've installed chromedriver so I can run tests via chrome.
Mocha and Nightwatch are also installed.
I've created a script called nightwatch inside the scripts object.
This will run nightwatch with mocha when I run npm run nightwatch from the command line when I'm located in the root of the project.
In addition, using the nightwatch.json or nightwatch.conf.js keeps that configuration out of your tests - you don't want to have to initialize that whenever you are writing a new test suite when you can do it once and be done.
Try invoking the done() callback in the end of the chain instead. I'm not fully up to speed with client.start(), but I'm quite sure you want to signal the test is done when the chain has reached its end.
var nightwatch = require('nightwatch');
describe('Google', function() {
var client = nightwatch.initClient({
// Pass here options from nightwatch.json
// selenium logs; change it to true if you want to see them in console
silent : false,
desiredCapabilities: {
browserName: "chrome",
javascriptEnabled: true,
acceptSslCerts: true
}
});
var browser = client.api();
// Mocha timeout
this.timeout(15000);
it('Demo test Google', function (done) {
browser
.url('http://www.google.com')
.waitForElementVisible('body', 1000)
.setValue('input[type=text]', 'nightwatch')
.waitForElementVisible('button[name=btnG]', 1000)
.click('button[name=btnG]')
.pause(1000)
.assert.containsText('#main', 'Night Watch')
.end(done);
client.start();
});
});