Skip to content

Commit

Permalink
Add more cases to k6 #4261
Browse files Browse the repository at this point in the history
ref DEV-1303
  • Loading branch information
tung2744 authored Jun 3, 2024
2 parents c82398b + 9e299f9 commit 2030ab6
Show file tree
Hide file tree
Showing 21 changed files with 1,205 additions and 28 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,6 @@ pkg/lib/webparcel/parcel_gen.go

# OSX
.DS_Store

# custom build of k6
/k6/k6
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ vendor:
go install github.com/google/wire/cmd/wire
go install golang.org/x/vuln/cmd/govulncheck@latest
go install golang.org/x/tools/cmd/goimports@latest
go install go.k6.io/xk6/cmd/xk6@latest
npm --prefix ./scripts/npm ci
npm --prefix ./authui ci
npm --prefix ./portal ci
Expand All @@ -45,6 +46,7 @@ generate:

.PHONY: test
test:
$(MAKE) -C ./k6 go-test
go test ./pkg/... -timeout 1m30s

.PHONY: lint
Expand Down
34 changes: 28 additions & 6 deletions k6/Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
#export K6_HTTP_DEBUG=true
# We cannot use K6_DURATION and K6_VUS because
# using them will make k6 to ignore scenarios.
export DURATION=10s
export VUS=10
export ENDPOINT=http://localhost:3100
export ENDPOINT=https://loadtest.authgear-loadtest.com
export CLIENT_ID=test
export REDIRECT_URI=com.example://host
export FIXTURE_FIXED_OTP=000000
Expand All @@ -13,14 +11,38 @@ export FIXTURE_PHONE_NUMBER_COUNTRY_CALLING_CODE=+852
export FIXTURE_PHONE_NUMBER_LOW=52000000
export FIXTURE_PHONE_NUMBER_HIGH=57999999

.PHONY: go-test
go-test:
go test .

.PHONY: k6
k6:
xk6 build --with github.com/authgear/authgear-server/k6=.

.PHONY: clean
clean:
rm -rf ./k6

.PHONY: signup
signup:
k6 run --vus $(VUS) --duration $(DURATION) ./signup.js
./k6 run --config options.json ./signup.js

.PHONY: login
login:
k6 run --vus $(VUS) --duration $(DURATION) ./login.js
./k6 run --config options.json ./login.js

.PHONY: refresh_access_token
refresh_access_token:
./k6 run --config options.json ./refresh_access_token.js

.PHONY: get_user_info
get_user_info:
./k6 run --config options.json ./get_user_info.js

.PHONY: biometric_login
biometric_login:
./k6 run --config options.json ./biometric_login.js

.PHONY: healthz
healthz:
k6 run --vus $(VUS) --duration $(DURATION) ./healthz.js
./k6 run --config options.json ./healthz.js
22 changes: 16 additions & 6 deletions k6/authflow.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export function authflowCreate({ type, name, questionMarkQuery }) {
const json = response.json();
const checkResult = checkJSON(json);
if (!checkResult) {
fail(`failed to create authflow ${type}:${name}`);
fail(`failed to create authflow ${type}:${name} ${JSON.stringify(json)}`);
}
return {
response,
Expand All @@ -66,7 +66,7 @@ export function authflowInput({ result, input }) {
const json = response.json();
const checkResult = checkJSON(json);
if (!checkResult) {
fail(`failed to input: ${state_token}`);
fail(`failed to input: ${state_token} ${JSON.stringify(json)}`);
}
return {
response,
Expand All @@ -82,12 +82,12 @@ export function redirect(result) {
typeof r.action.data.finish_redirect_uri === "string",
});
if (!checkResult) {
fail(`unexpected action: ${result.action}`);
fail(`unexpected action: ${result}`);
}
return http.get(result.action.data.finish_redirect_uri);
}

function authflowIdentify({ phone, email, result }) {
function authflowIdentify({ username, phone, email, result }) {
const options = result.action.data.options;
const first = options[0];
switch (first.identification) {
Expand All @@ -107,6 +107,14 @@ function authflowIdentify({ phone, email, result }) {
login_id: phone,
},
});
case "username":
return authflowInput({
result,
input: {
identification: "username",
login_id: username,
},
});
default:
throw new Error("unexpected identification: ", first.identification);
}
Expand Down Expand Up @@ -223,7 +231,7 @@ function authflowAuthenticate({ result }) {
}
}

export function authflowRun({ phone, email, type, name }) {
export function authflowRun({ username, phone, email, type, name }) {
const url = makeAuthenticationURL({
endpoint: ENDPOINT,
client_id: CLIENT_ID,
Expand All @@ -243,7 +251,7 @@ export function authflowRun({ phone, email, type, name }) {
while (ret.result.action.type !== "finished") {
switch (ret.result.action.type) {
case "identify":
ret = authflowIdentify({ phone, email, result: ret.result });
ret = authflowIdentify({ username, phone, email, result: ret.result });
break;
case "verify":
ret = authflowVerify({ result: ret.result });
Expand Down Expand Up @@ -274,4 +282,6 @@ export function authflowRun({ phone, email, type, name }) {
if (!checkResult) {
fail("failed to exchange code");
}

return tokenResponse;
}
2 changes: 2 additions & 0 deletions k6/authgear.features.yaml.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
rate_limits:
disabled: true
135 changes: 135 additions & 0 deletions k6/authgear.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package authgear

import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/json"
"encoding/pem"
"strings"

"github.com/google/uuid"
"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/lestrrat-go/jwx/v2/jws"
"go.k6.io/k6/js/modules"
)

func init() {
modules.Register("k6/x/authgear", new(Authgear))
}

func toJavaScript(v interface{}) interface{} {
b, err := json.Marshal(v)
if err != nil {
panic(err)
}
var out interface{}
err = json.Unmarshal(b, &out)
if err != nil {
panic(err)
}
return out
}

func toJSONBytes(v interface{}) []byte {
b, err := json.Marshal(v)
if err != nil {
panic(err)
}
return b
}

type Authgear struct{}

func (*Authgear) Uuid() string {
return uuid.Must(uuid.NewRandom()).String()
}

func (*Authgear) GenerateRSAPrivateKeyInPKCS8PEM(bits int) string {
key, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
panic(err)
}

der, err := x509.MarshalPKCS8PrivateKey(key)
if err != nil {
panic(err)
}

block := &pem.Block{
Type: "PRIVATE KEY",
Bytes: der,
}
var buf strings.Builder
err = pem.Encode(&buf, block)
if err != nil {
panic(err)
}

return buf.String()
}

func (*Authgear) JwkKeyFromPKCS8PEM(pkcs8Pem string) interface{} {
key, err := jwk.ParseKey([]byte(pkcs8Pem), jwk.WithPEM(true))
if err != nil {
panic(err)
}

return toJavaScript(key)
}

func (*Authgear) JwkPublicKeyFromJWKPrivateKey(jwkValue interface{}) interface{} {
jwkBytes := toJSONBytes(jwkValue)
jwkPrivateKey, err := jwk.ParseKey(jwkBytes)
if err != nil {
panic(err)
}
jwkPublicKey, err := jwkPrivateKey.PublicKey()
if err != nil {
panic(err)
}

return toJavaScript(jwkPublicKey)
}

func (*Authgear) SignJWT(alg string, jwkValue interface{}, payload interface{}, headers map[string]interface{}) string {
jwkBytes := toJSONBytes(jwkValue)
jwkPrivateKey, err := jwk.ParseKey(jwkBytes)
if err != nil {
panic(err)
}

payloadBytes := toJSONBytes(payload)

hdr := jws.NewHeaders()
for k, v := range headers {
switch k {
case "jwk":
jwkKey, err := jwk.ParseKey(toJSONBytes(v))
if err != nil {
panic(err)
}
err = hdr.Set(k, jwkKey)
default:
err = hdr.Set(k, v)
}
if err != nil {
panic(err)
}
}

b, err := jws.Sign(
payloadBytes,
jws.WithKey(
jwa.SignatureAlgorithm(alg),
jwkPrivateKey,
jws.WithProtectedHeaders(hdr),
),
)
if err != nil {
panic(err)
}

return string(b)
}
62 changes: 62 additions & 0 deletions k6/authgear.yaml.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
authentication:
identities:
- login_id
primary_authenticators:
- password
secondary_authentication_mode: disabled
authenticator:
oob_otp:
sms:
phone_otp_mode: sms
http:
public_origin: http://localhost:3100
id: loadtest
identity:
login_id:
keys:
- type: email
localization:
fallback_language: en
supported_languages:
- en
oauth:
clients:
- access_token_lifetime_seconds: 300
client_id: test
client_name: loadtest
grant_types:
- authorization_code
- refresh_token
issue_jwt_access_token: true
name: loadtest
redirect_uris:
- "com.example://host"
response_types:
- none
- code
test_mode:
oob_otp:
enabled: true
rules:
- fixed_code: "000000"
regex: .+
sms:
enabled: true
rules:
- regex: .+
suppressed: true
email:
enabled: true
rules:
- regex: .+
suppressed: true
ui:
implementation: authflowv2
verification:
claims:
email:
enabled: true
required: false
phone_number:
enabled: true
required: false
Loading

0 comments on commit 2030ab6

Please sign in to comment.