|
| 1 | +name: Cypress e2e integration tests workflow with security |
| 2 | +on: |
| 3 | + pull_request: |
| 4 | + branches: |
| 5 | + - "*" |
| 6 | + push: |
| 7 | + branches: |
| 8 | + - "*" |
| 9 | +env: |
| 10 | + OS_BRANCH: "3.3" |
| 11 | + SECURITY_ENABLED: "true" |
| 12 | + VERSION: "3.3.2" |
| 13 | + OPENSEARCH_INITIAL_ADMIN_PASSWORD: "myStrongPassword123!" |
| 14 | +jobs: |
| 15 | + tests: |
| 16 | + name: Run Cypress E2E tests for WLM |
| 17 | + timeout-minutes: 90 |
| 18 | + strategy: |
| 19 | + fail-fast: false |
| 20 | + matrix: |
| 21 | + os: [ ubuntu-latest ] |
| 22 | + include: |
| 23 | + - os: ubuntu-latest |
| 24 | + cypress_cache_folder: ~/.cache/Cypress |
| 25 | + runs-on: ${{ matrix.os }} |
| 26 | + env: |
| 27 | + # prevents extra Cypress installation progress messages |
| 28 | + CI: 1 |
| 29 | + # avoid warnings like "tput: No value for $TERM and no -T specified" |
| 30 | + TERM: xterm |
| 31 | + # make Node run in ipv4 first so that cypress can detect 5601 port in CI environment |
| 32 | + NODE_OPTIONS: '--max-old-space-size=6144 --dns-result-order=ipv4first' |
| 33 | + # 2.12 onwards security demo configuration require a custom admin password |
| 34 | + OPENSEARCH_INITIAL_ADMIN_PASSWORD: 'myStrongPassword123!' |
| 35 | + steps: |
| 36 | + - name: Checkout Branch |
| 37 | + uses: actions/checkout@v3 |
| 38 | + - name: Set up JDK |
| 39 | + uses: actions/setup-java@v1 |
| 40 | + with: |
| 41 | + java-version: 21 |
| 42 | + - name: Checkout cypress-test |
| 43 | + uses: actions/checkout@v2 |
| 44 | + with: |
| 45 | + repository: ${{github.repository}} |
| 46 | + path: cypress-test |
| 47 | + |
| 48 | + - name: Checkout Security |
| 49 | + uses: actions/checkout@v4 |
| 50 | + with: |
| 51 | + repository: opensearch-project/security |
| 52 | + path: security |
| 53 | + ref: ${{ env.OS_BRANCH }} |
| 54 | + |
| 55 | + - name: Build Security plugin |
| 56 | + run: | |
| 57 | + set -e |
| 58 | + cd security |
| 59 | + ./gradlew --no-daemon assemble |
| 60 | +
|
| 61 | + echo "Checking security build directory:" |
| 62 | + ls -la build/distributions/ |
| 63 | +
|
| 64 | + cp build/distributions/opensearch-security-*.zip "$GITHUB_WORKSPACE/security.zip" |
| 65 | + ls -lh "$GITHUB_WORKSPACE/security.zip" |
| 66 | +
|
| 67 | + - name: Checkout OpenSearch |
| 68 | + uses: actions/checkout@v4 |
| 69 | + with: |
| 70 | + path: OpenSearch |
| 71 | + repository: opensearch-project/OpenSearch |
| 72 | + ref: ${{ env.OS_BRANCH }} |
| 73 | + |
| 74 | + - name: Build WLM plugin from OpenSearch |
| 75 | + run: | |
| 76 | + set -e |
| 77 | + echo "Using OpenSearch branch: $OS_BRANCH" |
| 78 | + cd OpenSearch |
| 79 | +
|
| 80 | + # Build ONLY the workload-management plugin |
| 81 | + ./gradlew :plugins:workload-management:clean :plugins:workload-management:assemble \ |
| 82 | + -Dopensearch.version=${{ env.VERSION }} --no-daemon |
| 83 | +
|
| 84 | + echo "Checking WLM build directory:" |
| 85 | + ls -la plugins/workload-management/build/distributions/ |
| 86 | +
|
| 87 | + cp plugins/workload-management/build/distributions/workload-management-*.zip "$GITHUB_WORKSPACE/wlm.zip" |
| 88 | + ls -lh "$GITHUB_WORKSPACE/wlm.zip" |
| 89 | +
|
| 90 | + - name: Run Opensearch with A Single Plugin |
| 91 | + uses: derek-ho/start-opensearch@v9 |
| 92 | + with: |
| 93 | + opensearch-version: ${{ env.VERSION }} |
| 94 | + plugins: "file:$GITHUB_WORKSPACE/security.zip,file:$GITHUB_WORKSPACE/wlm.zip" |
| 95 | + security-enabled: true |
| 96 | + admin-password: ${{ env.OPENSEARCH_INITIAL_ADMIN_PASSWORD }} |
| 97 | + jdk-version: 21 |
| 98 | + |
| 99 | + - name: Enable WLM (with or without Security) and verify |
| 100 | + run: | |
| 101 | + set -e |
| 102 | + echo "Enabling Workload Management (WLM)..." |
| 103 | +
|
| 104 | + # Detect whether security is enabled |
| 105 | + if [ "$SECURITY_ENABLED" = 'true' ]; then |
| 106 | + echo "Security detected — using HTTPS with credentials" |
| 107 | + PROTOCOL=https |
| 108 | + AUTH="-u admin:${OPENSEARCH_INITIAL_ADMIN_PASSWORD}" |
| 109 | + CURL_FLAGS="--insecure --fail-with-body" |
| 110 | + else |
| 111 | + echo "No security detected — using HTTP without credentials" |
| 112 | + PROTOCOL=http |
| 113 | + AUTH="" |
| 114 | + CURL_FLAGS="--fail-with-body" |
| 115 | + fi |
| 116 | +
|
| 117 | + # Enable WLM |
| 118 | + curl -sS -k --http1.1 $CURL_FLAGS $AUTH \ |
| 119 | + -X PUT "${PROTOCOL}://localhost:9200/_cluster/settings" \ |
| 120 | + -H 'Content-Type: application/json' \ |
| 121 | + -d '{"persistent":{"wlm.workload_group.mode":"enabled"}}' |
| 122 | +
|
| 123 | + # Show WLM mode |
| 124 | + SETTINGS=$(curl -sS -k --http1.1 -u "admin:${OPENSEARCH_INITIAL_ADMIN_PASSWORD}" "https://localhost:9200/_cluster/settings") |
| 125 | + echo "Raw settings response: $SETTINGS" |
| 126 | + echo "$SETTINGS" | jq -r '.persistent.wlm.workload_group.mode // "undefined"' |
| 127 | +
|
| 128 | + # Test WLM stats endpoint |
| 129 | + echo -e "Testing WLM stats endpoint:" |
| 130 | + curl -ksu "admin:${OPENSEARCH_INITIAL_ADMIN_PASSWORD}" https://localhost:9200/_wlm/workload_group | jq '.' |
| 131 | +
|
| 132 | + - name: Checkout OpenSearch-Dashboards |
| 133 | + uses: actions/checkout@v4 |
| 134 | + with: |
| 135 | + repository: opensearch-project/OpenSearch-Dashboards |
| 136 | + path: OpenSearch-Dashboards |
| 137 | + ref: ${{ env.OS_BRANCH }} |
| 138 | + |
| 139 | + - name: Configure OpenSearch Dashboards for Cypress (heredoc) |
| 140 | + run: | |
| 141 | + set -euo pipefail |
| 142 | + FILE="OpenSearch-Dashboards/config/opensearch_dashboards.yml" |
| 143 | + test -f "$FILE" || { echo "Missing $FILE"; exit 1; } |
| 144 | +
|
| 145 | + { |
| 146 | + printf '%s\n' 'server.host: "0.0.0.0"' |
| 147 | + printf '%s\n' 'opensearch.hosts: ["https://localhost:9200"]' |
| 148 | + printf '%s\n' 'opensearch.ssl.verificationMode: none' |
| 149 | + } >> "$FILE" |
| 150 | +
|
| 151 | + echo "=== Last 60 lines of $FILE (show appended settings) ===" |
| 152 | + tail -n 60 "$FILE" || true |
| 153 | +
|
| 154 | + - name: Checkout Query Insights Dashboards plugin |
| 155 | + uses: actions/checkout@v4 |
| 156 | + with: |
| 157 | + path: OpenSearch-Dashboards/plugins/query-insights-dashboards |
| 158 | + |
| 159 | + - name: Setup Node |
| 160 | + uses: actions/setup-node@v3 |
| 161 | + with: |
| 162 | + node-version-file: './OpenSearch-Dashboards/.nvmrc' |
| 163 | + registry-url: 'https://registry.npmjs.org' |
| 164 | + |
| 165 | + - name: Install Yarn |
| 166 | + shell: bash |
| 167 | + run: | |
| 168 | + YARN_VERSION=$(node -p "require('./OpenSearch-Dashboards/package.json').engines.yarn") |
| 169 | + echo "Installing yarn@$YARN_VERSION" |
| 170 | + npm i -g yarn@$YARN_VERSION |
| 171 | + - run: node -v |
| 172 | + - run: yarn -v |
| 173 | + |
| 174 | + - name: Bootstrap plugin/OpenSearch-Dashboards |
| 175 | + run: | |
| 176 | + cd OpenSearch-Dashboards/plugins/query-insights-dashboards |
| 177 | + yarn osd bootstrap --single-version=loose |
| 178 | +
|
| 179 | + - name: Run OpenSearch-Dashboards server |
| 180 | + run: | |
| 181 | + cd OpenSearch-Dashboards |
| 182 | + export NODE_OPTIONS="--max-old-space-size=6144 --dns-result-order=ipv4first" |
| 183 | + echo "Starting Dashboards..." |
| 184 | + nohup yarn start --no-base-path --no-watch --server.host="0.0.0.0" > dashboards.log 2>&1 & |
| 185 | + sleep 10 |
| 186 | + echo "Initial Dashboards log output:" |
| 187 | + head -n 100 dashboards.log || true |
| 188 | + shell: bash |
| 189 | + |
| 190 | + - name: Wait for OpenSearch-Dashboards to be ready |
| 191 | + run: | |
| 192 | + echo "Waiting for OpenSearch-Dashboards to start..." |
| 193 | + max_attempts=180 |
| 194 | + attempt=0 |
| 195 | + while [ $attempt -lt $max_attempts ]; do |
| 196 | + code=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:5601/api/status || true) |
| 197 | + if [ "$code" = "200" ]; then |
| 198 | + state=$(curl -s http://localhost:5601/api/status | jq -r '.status.overall.state // .status.overall.level // "unknown"') |
| 199 | + echo "OpenSearch-Dashboards is ready (state=$state)" |
| 200 | + break |
| 201 | + fi |
| 202 | + attempt=$((attempt + 1)) |
| 203 | + echo "Attempt $attempt/$max_attempts: /api/status -> $code; waiting 10s..." |
| 204 | + if [ $((attempt % 10)) -eq 0 ]; then |
| 205 | + echo "=== tail dashboards.log ===" |
| 206 | + tail -n 120 OpenSearch-Dashboards/dashboards.log || true |
| 207 | + echo "=== tail $LOCAL_DISTRO/os.log ===" |
| 208 | + tail -n 200 OpenSearch/$LOCAL_DISTRO/os.log || true |
| 209 | + echo "===========================" |
| 210 | + fi |
| 211 | + sleep 10 |
| 212 | + done |
| 213 | + [ $attempt -lt $max_attempts ] || { echo "Timeout waiting for Dashboards"; tail -n 200 OpenSearch-Dashboards/dashboards.log || true; exit 1; } |
| 214 | +
|
| 215 | + - name: Verify services are running |
| 216 | + run: | |
| 217 | + echo "Checking OpenSearch status..." |
| 218 | + curl -ksu admin:myStrongPassword123! https://localhost:9200/_cluster/health | jq '.' || echo "OpenSearch not responding" |
| 219 | +
|
| 220 | + echo "Checking OpenSearch-Dashboards status..." |
| 221 | + echo "=== Full OpenSearch-Dashboards Status ===" |
| 222 | + curl -s http://localhost:5601/api/status || echo "OpenSearch-Dashboards not responding" |
| 223 | + echo "========================================" |
| 224 | +
|
| 225 | + echo "Checking OpenSearch-Dashboards overall state..." |
| 226 | + curl -s http://localhost:5601/api/status | jq '.status.overall.state' || echo "Could not extract overall state" |
| 227 | +
|
| 228 | + echo "Checking plugin endpoint..." |
| 229 | + # 1) login and store session cookie |
| 230 | + curl -s -c cookies.txt -X POST 'http://localhost:5601/auth/login' \ |
| 231 | + -H 'osd-xsrf: true' -H 'Content-Type: application/json' \ |
| 232 | + --data "{\"username\":\"admin\",\"password\":\"${OPENSEARCH_INITIAL_ADMIN_PASSWORD}\"}" >/dev/null |
| 233 | +
|
| 234 | + # 2) hit the app route using the cookie |
| 235 | + curl -s -b cookies.txt -o /dev/null -w "HTTP:%{http_code}\n" \ |
| 236 | + 'http://localhost:5601/app/query-insights-dashboards' || echo "Plugin endpoint not accessible" |
| 237 | + shell: bash |
| 238 | + continue-on-error: true |
| 239 | + |
| 240 | + - name: Install Cypress |
| 241 | + run: | |
| 242 | + cd OpenSearch-Dashboards/plugins/query-insights-dashboards |
| 243 | + npx cypress install |
| 244 | + shell: bash |
| 245 | + |
| 246 | + - name: Get Cypress version |
| 247 | + id: cypress_version |
| 248 | + run: | |
| 249 | + cd OpenSearch-Dashboards/plugins/query-insights-dashboards |
| 250 | + echo "::set-output name=cypress_version::$(cat ./package.json | jq '.dependencies.cypress' | tr -d '"')" |
| 251 | +
|
| 252 | + - name: Cache Cypress |
| 253 | + id: cache-cypress |
| 254 | + uses: actions/cache@v4 |
| 255 | + with: |
| 256 | + path: ${{ matrix.cypress_cache_folder }} |
| 257 | + key: cypress-cache-v2-${{ matrix.os }}-${{ hashFiles('OpenSearch-Dashboards/plugins/query-insights-dashboards/package.json') }} |
| 258 | + |
| 259 | + - name: Create WLM workload group |
| 260 | + run: | |
| 261 | + curl -ksu admin:"${OPENSEARCH_INITIAL_ADMIN_PASSWORD}" \ |
| 262 | + -H 'Content-Type: application/json' \ |
| 263 | + -X PUT 'https://localhost:9200/_wlm/workload_group' \ |
| 264 | + -d '{"name":"test_group","resiliency_mode":"soft","resource_limits":{"cpu":0.1,"memory":0.1}}' |
| 265 | +
|
| 266 | + - name: Cypress tests |
| 267 | + uses: cypress-io/github-action@v5 |
| 268 | + with: |
| 269 | + working-directory: OpenSearch-Dashboards/plugins/query-insights-dashboards |
| 270 | + command: yarn run cypress run --config defaultCommandTimeout=120000,requestTimeout=120000,responseTimeout=120000,pageLoadTimeout=180000,taskTimeout=120000,execTimeout=120000,excludeSpecPattern=cypress/e2e/qi/**/* |
| 271 | + browser: chrome |
| 272 | + env: |
| 273 | + CYPRESS_CACHE_FOLDER: ${{ matrix.cypress_cache_folder }} |
| 274 | + CI: true |
| 275 | + timeout-minutes: 120 |
| 276 | + |
| 277 | + - uses: actions/upload-artifact@v4 |
| 278 | + if: failure() |
| 279 | + with: |
| 280 | + name: cypress-screenshots-${{ matrix.os }} |
| 281 | + path: OpenSearch-Dashboards/plugins/query-insights-dashboards/cypress/screenshots |
| 282 | + |
| 283 | + - uses: actions/upload-artifact@v4 |
| 284 | + if: always() |
| 285 | + with: |
| 286 | + name: cypress-videos-${{ matrix.os }} |
| 287 | + path: OpenSearch-Dashboards/plugins/query-insights-dashboards/cypress/videos |
0 commit comments