mirror of
https://github.com/iflytek/skillhub.git
synced 2026-08-27 11:14:59 +00:00
test: cover namespace workflow smoke paths
This commit is contained in:
parent
30d6581710
commit
62979b2dd7
4 changed files with 462 additions and 1 deletions
5
Makefile
5
Makefile
|
|
@ -1,4 +1,4 @@
|
|||
.PHONY: help dev dev-all dev-down dev-all-down dev-all-reset dev-logs dev-status build test clean web-install dev-server dev-server-restart dev-web build-web test-web typecheck-web lint-web generate-api db-reset validate-release-config staging staging-down staging-logs pr parallel-init parallel-sync parallel-up parallel-down
|
||||
.PHONY: help dev dev-all dev-down dev-all-down dev-all-reset dev-logs dev-status build test clean web-install dev-server dev-server-restart dev-web build-web test-web typecheck-web lint-web generate-api db-reset namespace-smoke validate-release-config staging staging-down staging-logs pr parallel-init parallel-sync parallel-up parallel-down
|
||||
|
||||
DEV_DIR := .dev
|
||||
DEV_SERVER_PID := $(DEV_DIR)/server.pid
|
||||
|
|
@ -117,6 +117,9 @@ dev-server-restart: ## 重启后端开发服务器
|
|||
echo "Backend failed to become ready. Check $(DEV_SERVER_LOG)"; \
|
||||
exit 1
|
||||
|
||||
namespace-smoke: ## 运行命名空间工作流 smoke test
|
||||
./scripts/namespace-smoke-test.sh $(DEV_API_URL)
|
||||
|
||||
dev-down: ## 停止本地开发环境
|
||||
$(DEV_COMPOSE) down --remove-orphans
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ Two mock users are available in local mode (no password needed):
|
|||
| `SERVICE=frontend make dev-logs` | Tail frontend logs |
|
||||
| `make dev-all-reset` | Full reset (clears data volumes) |
|
||||
| `make dev-server-restart` | Restart backend after Java changes |
|
||||
| `make namespace-smoke` | Run namespace workflow smoke test |
|
||||
| `make db-reset` | Reset database only |
|
||||
|
||||
### Claude + Codex parallel workflow
|
||||
|
|
|
|||
257
scripts/namespace-smoke-test.sh
Executable file
257
scripts/namespace-smoke-test.sh
Executable file
|
|
@ -0,0 +1,257 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
BASE_URL="${1:-http://localhost:8080}"
|
||||
PASS=0
|
||||
FAIL=0
|
||||
USER_COOKIE="$(mktemp)"
|
||||
ADMIN_COOKIE="$(mktemp)"
|
||||
SLUG="nsmoke$(date +%s)"
|
||||
|
||||
cleanup() {
|
||||
rm -f "$USER_COOKIE" "$ADMIN_COOKIE"
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
pass() {
|
||||
echo "PASS: $1"
|
||||
PASS=$((PASS + 1))
|
||||
}
|
||||
|
||||
fail() {
|
||||
echo "FAIL: $1"
|
||||
FAIL=$((FAIL + 1))
|
||||
}
|
||||
|
||||
csrf_token() {
|
||||
local cookie_file="$1"
|
||||
awk '$6 == "XSRF-TOKEN" { print $7 }' "$cookie_file" | tail -n 1
|
||||
}
|
||||
|
||||
bootstrap_csrf() {
|
||||
local cookie_file="$1"
|
||||
local user_id="$2"
|
||||
curl -s -c "$cookie_file" -H "X-Mock-User-Id: $user_id" "$BASE_URL/api/v1/auth/providers" >/dev/null
|
||||
}
|
||||
|
||||
json_field() {
|
||||
local json="$1"
|
||||
local expr="$2"
|
||||
JSON_INPUT="$json" python3 - "$expr" <<'PY'
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
expr = sys.argv[1]
|
||||
data = json.loads(os.environ["JSON_INPUT"])
|
||||
value = data
|
||||
for part in expr.split('.'):
|
||||
if part.isdigit():
|
||||
value = value[int(part)]
|
||||
else:
|
||||
value = value[part]
|
||||
if isinstance(value, (dict, list)):
|
||||
print(json.dumps(value, ensure_ascii=False))
|
||||
else:
|
||||
print(value)
|
||||
PY
|
||||
}
|
||||
|
||||
assert_code() {
|
||||
local description="$1"
|
||||
local json="$2"
|
||||
local expected="$3"
|
||||
local actual
|
||||
actual="$(json_field "$json" "code")"
|
||||
if [[ "$actual" == "$expected" ]]; then
|
||||
pass "$description"
|
||||
else
|
||||
fail "$description (expected code $expected, got $actual)"
|
||||
fi
|
||||
}
|
||||
|
||||
USER_HEADERS=(-H "X-Mock-User-Id: local-user" -b "$USER_COOKIE" -c "$USER_COOKIE")
|
||||
ADMIN_HEADERS=(-H "X-Mock-User-Id: local-admin" -b "$ADMIN_COOKIE" -c "$ADMIN_COOKIE")
|
||||
|
||||
echo "=== Namespace Workflow Smoke Test ==="
|
||||
echo "Target: $BASE_URL"
|
||||
echo "Slug: $SLUG"
|
||||
echo
|
||||
|
||||
bootstrap_csrf "$USER_COOKIE" "local-user"
|
||||
bootstrap_csrf "$ADMIN_COOKIE" "local-admin"
|
||||
|
||||
USER_CSRF="$(csrf_token "$USER_COOKIE")"
|
||||
ADMIN_CSRF="$(csrf_token "$ADMIN_COOKIE")"
|
||||
|
||||
if [[ -z "$USER_CSRF" || -z "$ADMIN_CSRF" ]]; then
|
||||
echo "Could not bootstrap CSRF tokens"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CREATE_RESPONSE="$(curl -sS "${USER_HEADERS[@]}" \
|
||||
-H "X-XSRF-TOKEN: $USER_CSRF" \
|
||||
-H "Content-Type: application/json" \
|
||||
-X POST "$BASE_URL/api/web/namespaces" \
|
||||
-d "{\"slug\":\"$SLUG\",\"displayName\":\"Namespace Smoke $SLUG\",\"description\":\"namespace workflow smoke test\"}")"
|
||||
assert_code "Owner can create namespace" "$CREATE_RESPONSE" "0"
|
||||
NAMESPACE_ID="$(json_field "$CREATE_RESPONSE" "data.id")"
|
||||
|
||||
MINE_RESPONSE="$(curl -sS "${USER_HEADERS[@]}" "$BASE_URL/api/web/me/namespaces")"
|
||||
assert_code "Owner can list my namespaces" "$MINE_RESPONSE" "0"
|
||||
if JSON_INPUT="$MINE_RESPONSE" python3 - "$SLUG" <<'PY'
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
slug = sys.argv[1]
|
||||
data = json.loads(os.environ["JSON_INPUT"])
|
||||
items = data["data"]
|
||||
match = next((item for item in items if item["slug"] == slug), None)
|
||||
if not match:
|
||||
raise SystemExit(1)
|
||||
if match["currentUserRole"] != "OWNER":
|
||||
raise SystemExit(2)
|
||||
if match["status"] != "ACTIVE":
|
||||
raise SystemExit(3)
|
||||
PY
|
||||
then
|
||||
pass "Created namespace shows up as ACTIVE owner namespace"
|
||||
else
|
||||
fail "Created namespace should appear in owner namespace list with OWNER role"
|
||||
fi
|
||||
|
||||
ADMIN_MINE_RESPONSE="$(curl -sS "${ADMIN_HEADERS[@]}" "$BASE_URL/api/web/me/namespaces")"
|
||||
assert_code "Other user can list my namespaces" "$ADMIN_MINE_RESPONSE" "0"
|
||||
if JSON_INPUT="$ADMIN_MINE_RESPONSE" python3 - "$SLUG" <<'PY'
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
slug = sys.argv[1]
|
||||
data = json.loads(os.environ["JSON_INPUT"])
|
||||
items = data["data"]
|
||||
raise SystemExit(0 if all(item["slug"] != slug for item in items) else 1)
|
||||
PY
|
||||
then
|
||||
pass "Namespace is not visible to unrelated users in my namespaces"
|
||||
else
|
||||
fail "Unrelated user should not see team namespace in my namespaces"
|
||||
fi
|
||||
|
||||
FREEZE_FORBIDDEN_RESPONSE="$(curl -sS "${ADMIN_HEADERS[@]}" \
|
||||
-H "X-XSRF-TOKEN: $ADMIN_CSRF" \
|
||||
-X POST "$BASE_URL/api/web/namespaces/$SLUG/freeze")"
|
||||
assert_code "Unrelated user cannot freeze namespace" "$FREEZE_FORBIDDEN_RESPONSE" "403"
|
||||
|
||||
CANDIDATES_RESPONSE="$(curl -sS "${USER_HEADERS[@]}" "$BASE_URL/api/web/namespaces/$SLUG/member-candidates?search=local")"
|
||||
assert_code "Owner can search namespace member candidates" "$CANDIDATES_RESPONSE" "0"
|
||||
if JSON_INPUT="$CANDIDATES_RESPONSE" python3 - <<'PY'
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
data = json.loads(os.environ["JSON_INPUT"])
|
||||
ids = {item["userId"] for item in data["data"]}
|
||||
raise SystemExit(0 if "local-admin" in ids else 1)
|
||||
PY
|
||||
then
|
||||
pass "Candidate search returns local-admin"
|
||||
else
|
||||
fail "Candidate search should include local-admin"
|
||||
fi
|
||||
|
||||
ADD_MEMBER_RESPONSE="$(curl -sS "${USER_HEADERS[@]}" \
|
||||
-H "X-XSRF-TOKEN: $USER_CSRF" \
|
||||
-H "Content-Type: application/json" \
|
||||
-X POST "$BASE_URL/api/web/namespaces/$SLUG/members" \
|
||||
-d '{"userId":"local-admin","role":"MEMBER"}')"
|
||||
assert_code "Owner can add namespace members" "$ADD_MEMBER_RESPONSE" "0"
|
||||
|
||||
MEMBERS_RESPONSE="$(curl -sS "${USER_HEADERS[@]}" "$BASE_URL/api/web/namespaces/$SLUG/members")"
|
||||
assert_code "Owner can list namespace members" "$MEMBERS_RESPONSE" "0"
|
||||
if JSON_INPUT="$MEMBERS_RESPONSE" python3 - <<'PY'
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
data = json.loads(os.environ["JSON_INPUT"])
|
||||
items = data["data"]["items"]
|
||||
ids = {item["userId"] for item in items}
|
||||
raise SystemExit(0 if {"local-user", "local-admin"}.issubset(ids) else 1)
|
||||
PY
|
||||
then
|
||||
pass "Member list shows owner and invited admin user"
|
||||
else
|
||||
fail "Member list should contain owner and invited user"
|
||||
fi
|
||||
|
||||
REVIEWS_RESPONSE="$(curl -sS "${USER_HEADERS[@]}" "$BASE_URL/api/web/reviews?status=PENDING&namespaceId=$NAMESPACE_ID")"
|
||||
assert_code "Owner can open namespace review list" "$REVIEWS_RESPONSE" "0"
|
||||
|
||||
PROMOTE_RESPONSE="$(curl -sS "${USER_HEADERS[@]}" \
|
||||
-H "X-XSRF-TOKEN: $USER_CSRF" \
|
||||
-H "Content-Type: application/json" \
|
||||
-X PUT "$BASE_URL/api/web/namespaces/$SLUG/members/local-admin/role" \
|
||||
-d '{"role":"ADMIN"}')"
|
||||
assert_code "Owner can promote member to admin" "$PROMOTE_RESPONSE" "0"
|
||||
|
||||
ADMIN_FREEZE_RESPONSE="$(curl -sS "${ADMIN_HEADERS[@]}" \
|
||||
-H "X-XSRF-TOKEN: $ADMIN_CSRF" \
|
||||
-X POST "$BASE_URL/api/web/namespaces/$SLUG/freeze")"
|
||||
assert_code "Namespace admin can freeze namespace" "$ADMIN_FREEZE_RESPONSE" "0"
|
||||
if [[ "$(json_field "$ADMIN_FREEZE_RESPONSE" "data.status")" == "FROZEN" ]]; then
|
||||
pass "Freeze changes namespace status to FROZEN"
|
||||
else
|
||||
fail "Freeze should set namespace status to FROZEN"
|
||||
fi
|
||||
|
||||
ADD_WHILE_FROZEN_RESPONSE="$(curl -sS "${USER_HEADERS[@]}" \
|
||||
-H "X-XSRF-TOKEN: $USER_CSRF" \
|
||||
-H "Content-Type: application/json" \
|
||||
-X POST "$BASE_URL/api/web/namespaces/$SLUG/members" \
|
||||
-d '{"userId":"local-user","role":"MEMBER"}')"
|
||||
assert_code "Frozen namespace rejects member mutation" "$ADD_WHILE_FROZEN_RESPONSE" "400"
|
||||
|
||||
ADMIN_UNFREEZE_RESPONSE="$(curl -sS "${ADMIN_HEADERS[@]}" \
|
||||
-H "X-XSRF-TOKEN: $ADMIN_CSRF" \
|
||||
-X POST "$BASE_URL/api/web/namespaces/$SLUG/unfreeze")"
|
||||
assert_code "Namespace admin can unfreeze namespace" "$ADMIN_UNFREEZE_RESPONSE" "0"
|
||||
|
||||
ADMIN_ARCHIVE_RESPONSE="$(curl -sS "${ADMIN_HEADERS[@]}" \
|
||||
-H "X-XSRF-TOKEN: $ADMIN_CSRF" \
|
||||
-H "Content-Type: application/json" \
|
||||
-X POST "$BASE_URL/api/web/namespaces/$SLUG/archive" \
|
||||
-d '{"reason":"smoke"}')"
|
||||
assert_code "Namespace admin cannot archive namespace" "$ADMIN_ARCHIVE_RESPONSE" "403"
|
||||
|
||||
OWNER_ARCHIVE_RESPONSE="$(curl -sS "${USER_HEADERS[@]}" \
|
||||
-H "X-XSRF-TOKEN: $USER_CSRF" \
|
||||
-H "Content-Type: application/json" \
|
||||
-X POST "$BASE_URL/api/web/namespaces/$SLUG/archive" \
|
||||
-d '{"reason":"smoke"}')"
|
||||
assert_code "Owner can archive namespace" "$OWNER_ARCHIVE_RESPONSE" "0"
|
||||
if [[ "$(json_field "$OWNER_ARCHIVE_RESPONSE" "data.status")" == "ARCHIVED" ]]; then
|
||||
pass "Archive changes namespace status to ARCHIVED"
|
||||
else
|
||||
fail "Archive should set namespace status to ARCHIVED"
|
||||
fi
|
||||
|
||||
OWNER_RESTORE_RESPONSE="$(curl -sS "${USER_HEADERS[@]}" \
|
||||
-H "X-XSRF-TOKEN: $USER_CSRF" \
|
||||
-X POST "$BASE_URL/api/web/namespaces/$SLUG/restore")"
|
||||
assert_code "Owner can restore archived namespace" "$OWNER_RESTORE_RESPONSE" "0"
|
||||
if [[ "$(json_field "$OWNER_RESTORE_RESPONSE" "data.status")" == "ACTIVE" ]]; then
|
||||
pass "Restore changes namespace status back to ACTIVE"
|
||||
else
|
||||
fail "Restore should set namespace status back to ACTIVE"
|
||||
fi
|
||||
|
||||
REMOVE_MEMBER_RESPONSE="$(curl -sS "${USER_HEADERS[@]}" \
|
||||
-H "X-XSRF-TOKEN: $USER_CSRF" \
|
||||
-X DELETE "$BASE_URL/api/web/namespaces/$SLUG/members/local-admin")"
|
||||
assert_code "Owner can remove namespace admin" "$REMOVE_MEMBER_RESPONSE" "0"
|
||||
|
||||
echo
|
||||
echo "Results: $PASS passed, $FAIL failed"
|
||||
if [[ "$FAIL" -ne 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -0,0 +1,200 @@
|
|||
package com.iflytek.skillhub.controller;
|
||||
|
||||
import com.iflytek.skillhub.auth.device.DeviceAuthService;
|
||||
import com.iflytek.skillhub.auth.rbac.PlatformPrincipal;
|
||||
import com.iflytek.skillhub.domain.namespace.Namespace;
|
||||
import com.iflytek.skillhub.domain.namespace.NamespaceGovernanceService;
|
||||
import com.iflytek.skillhub.domain.namespace.NamespaceMember;
|
||||
import com.iflytek.skillhub.domain.namespace.NamespaceMemberRepository;
|
||||
import com.iflytek.skillhub.domain.namespace.NamespaceMemberService;
|
||||
import com.iflytek.skillhub.domain.namespace.NamespaceRepository;
|
||||
import com.iflytek.skillhub.domain.namespace.NamespaceRole;
|
||||
import com.iflytek.skillhub.domain.namespace.NamespaceService;
|
||||
import com.iflytek.skillhub.domain.namespace.NamespaceStatus;
|
||||
import com.iflytek.skillhub.domain.namespace.NamespaceType;
|
||||
import com.iflytek.skillhub.dto.NamespaceCandidateUserResponse;
|
||||
import com.iflytek.skillhub.service.NamespaceMemberCandidateService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.RequestPostProcessor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@SpringBootTest
|
||||
@AutoConfigureMockMvc
|
||||
@ActiveProfiles("test")
|
||||
class NamespaceWorkflowContractTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockBean
|
||||
private NamespaceService namespaceService;
|
||||
|
||||
@MockBean
|
||||
private NamespaceGovernanceService namespaceGovernanceService;
|
||||
|
||||
@MockBean
|
||||
private NamespaceMemberService namespaceMemberService;
|
||||
|
||||
@MockBean
|
||||
private NamespaceRepository namespaceRepository;
|
||||
|
||||
@MockBean
|
||||
private NamespaceMemberRepository namespaceMemberRepository;
|
||||
|
||||
@MockBean
|
||||
private NamespaceMemberCandidateService namespaceMemberCandidateService;
|
||||
|
||||
@MockBean
|
||||
private DeviceAuthService deviceAuthService;
|
||||
|
||||
@Test
|
||||
void namespaceWorkflowEndpoints_shareExpectedEnvelopeShapes() throws Exception {
|
||||
Namespace namespace = namespace(7L, "team-flow", NamespaceStatus.ACTIVE, NamespaceType.TEAM);
|
||||
Namespace frozen = namespace(7L, "team-flow", NamespaceStatus.FROZEN, NamespaceType.TEAM);
|
||||
Namespace archived = namespace(7L, "team-flow", NamespaceStatus.ARCHIVED, NamespaceType.TEAM);
|
||||
NamespaceMember adminMember = new NamespaceMember(7L, "user-admin", NamespaceRole.ADMIN);
|
||||
setMemberId(adminMember, 11L);
|
||||
|
||||
given(namespaceService.createNamespace(eq("team-flow"), eq("Team Flow"), eq("workflow"), eq("owner-1")))
|
||||
.willReturn(namespace);
|
||||
given(namespaceService.getNamespaceBySlug("team-flow")).willReturn(namespace);
|
||||
given(namespaceGovernanceService.freezeNamespace(eq("team-flow"), eq("owner-1"), eq(null), eq(null), any(), any()))
|
||||
.willReturn(frozen);
|
||||
given(namespaceGovernanceService.archiveNamespace(eq("team-flow"), eq("owner-1"), eq("cleanup"), eq(null), any(), any()))
|
||||
.willReturn(archived);
|
||||
given(namespaceMemberCandidateService.searchCandidates("team-flow", "admin", "owner-1", 10))
|
||||
.willReturn(List.of(new NamespaceCandidateUserResponse("user-admin", "Admin", "admin@example.com", "ACTIVE")));
|
||||
given(namespaceMemberService.addMember(7L, "user-admin", NamespaceRole.ADMIN, "owner-1"))
|
||||
.willReturn(adminMember);
|
||||
given(namespaceMemberService.listMembers(eq(7L), any(org.springframework.data.domain.Pageable.class)))
|
||||
.willReturn(new org.springframework.data.domain.PageImpl<>(List.of(adminMember)));
|
||||
given(namespaceMemberService.updateMemberRole(7L, "user-admin", NamespaceRole.ADMIN, "owner-1"))
|
||||
.willReturn(adminMember);
|
||||
|
||||
mockMvc.perform(post("/api/web/namespaces")
|
||||
.with(csrf())
|
||||
.with(auth("owner-1"))
|
||||
.requestAttr("userId", "owner-1")
|
||||
.contentType(org.springframework.http.MediaType.APPLICATION_JSON)
|
||||
.content("{\"slug\":\"team-flow\",\"displayName\":\"Team Flow\",\"description\":\"workflow\"}"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andExpect(jsonPath("$.data.slug").value("team-flow"));
|
||||
|
||||
mockMvc.perform(get("/api/web/namespaces/team-flow/member-candidates")
|
||||
.param("search", "admin")
|
||||
.with(auth("owner-1"))
|
||||
.requestAttr("userId", "owner-1"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andExpect(jsonPath("$.data[0].userId").value("user-admin"));
|
||||
|
||||
mockMvc.perform(post("/api/web/namespaces/team-flow/members")
|
||||
.with(csrf())
|
||||
.with(auth("owner-1"))
|
||||
.requestAttr("userId", "owner-1")
|
||||
.contentType(org.springframework.http.MediaType.APPLICATION_JSON)
|
||||
.content("{\"userId\":\"user-admin\",\"role\":\"ADMIN\"}"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andExpect(jsonPath("$.data.userId").value("user-admin"));
|
||||
|
||||
mockMvc.perform(get("/api/web/namespaces/team-flow/members")
|
||||
.with(auth("owner-1"))
|
||||
.requestAttr("userId", "owner-1"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andExpect(jsonPath("$.data.items[0].userId").value("user-admin"));
|
||||
|
||||
mockMvc.perform(put("/api/web/namespaces/team-flow/members/user-admin/role")
|
||||
.with(csrf())
|
||||
.with(auth("owner-1"))
|
||||
.requestAttr("userId", "owner-1")
|
||||
.contentType(org.springframework.http.MediaType.APPLICATION_JSON)
|
||||
.content("{\"role\":\"ADMIN\"}"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andExpect(jsonPath("$.data.role").value("ADMIN"));
|
||||
|
||||
mockMvc.perform(post("/api/web/namespaces/team-flow/freeze")
|
||||
.with(csrf())
|
||||
.with(auth("owner-1"))
|
||||
.requestAttr("userId", "owner-1"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andExpect(jsonPath("$.data.status").value("FROZEN"));
|
||||
|
||||
mockMvc.perform(post("/api/web/namespaces/team-flow/archive")
|
||||
.with(csrf())
|
||||
.with(auth("owner-1"))
|
||||
.requestAttr("userId", "owner-1")
|
||||
.contentType(org.springframework.http.MediaType.APPLICATION_JSON)
|
||||
.content("{\"reason\":\"cleanup\"}"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andExpect(jsonPath("$.data.status").value("ARCHIVED"));
|
||||
|
||||
mockMvc.perform(delete("/api/web/namespaces/team-flow/members/user-admin")
|
||||
.with(csrf())
|
||||
.with(auth("owner-1"))
|
||||
.requestAttr("userId", "owner-1"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andExpect(jsonPath("$.data.message").value("Member removed successfully"));
|
||||
}
|
||||
|
||||
private RequestPostProcessor auth(String userId) {
|
||||
PlatformPrincipal principal = new PlatformPrincipal(
|
||||
userId,
|
||||
userId,
|
||||
userId + "@example.com",
|
||||
"",
|
||||
"session",
|
||||
Set.of()
|
||||
);
|
||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
|
||||
principal,
|
||||
null,
|
||||
List.of(new SimpleGrantedAuthority("ROLE_USER"))
|
||||
);
|
||||
return authentication(authenticationToken);
|
||||
}
|
||||
|
||||
private Namespace namespace(Long id, String slug, NamespaceStatus status, NamespaceType type) {
|
||||
Namespace namespace = new Namespace(slug, "Team Flow", "owner-1");
|
||||
setNamespaceId(namespace, id);
|
||||
namespace.setStatus(status);
|
||||
namespace.setType(type);
|
||||
return namespace;
|
||||
}
|
||||
|
||||
private void setNamespaceId(Namespace namespace, Long id) {
|
||||
org.springframework.test.util.ReflectionTestUtils.setField(namespace, "id", id);
|
||||
}
|
||||
|
||||
private void setMemberId(NamespaceMember member, Long id) {
|
||||
org.springframework.test.util.ReflectionTestUtils.setField(member, "id", id);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue