Skip to content

Commit

Permalink
Merge pull request #1477 from serlo/staging
Browse files Browse the repository at this point in the history
Deployment
  • Loading branch information
hugotiburtino authored May 11, 2024
2 parents 145e80c + 6f1a9f8 commit 6490a91
Show file tree
Hide file tree
Showing 51 changed files with 1,545 additions and 1,782 deletions.
3 changes: 2 additions & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ ROCKET_CHAT_API_AUTH_TOKEN=an-auth-token
ROCKET_CHAT_URL=https://community.serlo.org/
SERLO_ORG_DATABASE_LAYER_HOST=127.0.0.1:8080
SERLO_ORG_SECRET=serlo.org-secret
CACHE_TYPE=empty
# Set the following value to `empty` to disable caching
CACHE_TYPE=redis

SERVER_HYDRA_HOST=http://localhost:4445
SERVER_KRATOS_PUBLIC_HOST=http://localhost:4433
Expand Down
7 changes: 6 additions & 1 deletion .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,12 @@ jobs:
- uses: serlo/configure-repositories/actions/setup-mysql@main
- uses: serlo/configure-repositories/actions/setup-node@main
- run: yarn start:containers
- run: yarn test
# It seems that running tests for changing taxonomies in parallel
# to metadata query messes up with internal optimizatons so that
# testing metadata endpoint runs into a timout
# => solution: Run tests for metadata in an extra step
- run: yarn test metadata.ts
- run: yarn test --testPathIgnorePatterns metadata.ts __utils__

codegen:
runs-on: ubuntu-latest
Expand Down
Binary file not shown.
Binary file not shown.
29 changes: 12 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Happy coding!

### Stop

Interrupt the `yarn start` command to stop the dev server and run `yarn stop:redis` to stop Redis.
Interrupt the `yarn start` command to stop the dev server and run `yarn down` to remove all containers.

### Automatically check your codebase before pushing

Expand All @@ -89,17 +89,6 @@ chmod +x .git/hooks/pre-push

With `git push --no-verify` you can bypass the automatic checks.

### Repository structure

- `__fixtures__` contains test data (used by both unit and contract tests).
- `__tests__` contains the unit tests.
- `__tests-pacts__` contains the contract test.
- `src/internals` contains a couple of internal data structures. In most cases, you won't need to touch this. Here we hide complexity that isn't needed for typical development tasks.
- `src/model` defines the model.
- `src/schema` defines the GraphQL schema.

We have `~` as an absolute path alias for `./src` in place, e.g. `~/internals` refers to `./src/internals`.

### Other commands

- `yarn build:server` builds the server (only needed for deployment)
Expand Down Expand Up @@ -129,14 +118,17 @@ For more info about it see its [documentation](https://www.ory.sh/docs/kratos).

### Integrating Keycloak

First of all add `nbp` as host
First of all add `nbp` and `vidis` as host
`sudo bash -c "echo '127.0.0.1 nbp'" >> /etc/hosts`
`sudo bash -c "echo '127.0.0.1 vidis'" >> /etc/hosts`

_why do I need it? Kratos makes a request to the url of the oauth2 provider, but since it is running inside a container, it cannot easily use the host port. nbp is a dns that is discoverable for the kratos container, so the host can also use it._
_why do I need it? Kratos makes a request to the url of the oauth2 provider, but since it is running inside a container, it cannot easily use the host port. These DNSs are discoverable for the kratos container, so the host can also use it._

Run `yarn start:nbp`.
Run `yarn start:sso`.
_Make sure you already run `yarn start:kratos` before._

Keycloak UI is available on `nbp:11111` (username: admin, pw: admin).
Keycloak UI is available on `nbp:11111` and `vidis:11112`.
Username: admin, pw: admin.
There you have to configure Serlo as a client.

> Client -> Create Client
Expand All @@ -145,6 +137,7 @@ There you have to configure Serlo as a client.
> id: serlo
> home and root url: http://localhost:3000
> redirect uri: http://localhost:4433/self-service/methods/oidc/callback/nbp
> // OR redirect uri: http://localhost:4433/self-service/methods/oidc/callback/vidis
> ```
Get the credentials and go to `kratos/config.yml`:
Expand All @@ -156,14 +149,16 @@ selfservice:
enabled: true
config:
providers:
- id: nbp
- id: nbp # or vidis
provider: generic
client_id: serlo
client_secret: <put secret here>
```
Run the local frontend (not forgetting to change environment in its `.env` to local) to test.

Hint: you may want to create some users in Keycloak in order to test.

### Email templates

Kratos has to be rebuilt every time you change an email template. Use the following workflow:
Expand Down
2 changes: 2 additions & 0 deletions __fixtures__/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from './license-id'
export * from './notification'
export * from './uuid'
export * from './subjects'
export * from './metadata'
10 changes: 10 additions & 0 deletions __fixtures__/subjects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const emptySubjects = [
{ unrevisedEntities: { nodes: [] } },
{ unrevisedEntities: { nodes: [] } },
{ unrevisedEntities: { nodes: [] } },
{ unrevisedEntities: { nodes: [] } },
{ unrevisedEntities: { nodes: [] } },
{ unrevisedEntities: { nodes: [] } },
{ unrevisedEntities: { nodes: [] } },
{ unrevisedEntities: { nodes: [] } },
]
29 changes: 29 additions & 0 deletions __tests__/__utils__/assertions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { type Storage } from '@google-cloud/storage'
import type { OAuth2Api } from '@ory/client'
import * as Sentry from '@sentry/node'
import { DocumentNode } from 'graphql'
import gql from 'graphql-tag'
import * as R from 'ramda'

import { given, nextUuid } from '.'
Expand Down Expand Up @@ -121,6 +122,8 @@ export class Query<
const result = await this.execute()

if (result.body.kind === 'single') {
expect(result.body.singleResult['errors']).toBeUndefined()

return result.body.singleResult['data']
}

Expand Down Expand Up @@ -237,6 +240,32 @@ export async function assertErrorEvent(args?: {
expect(global.sentryEvents.some(eventPredicate)).toBe(true)
}

export async function expectEvent(
event: {
__typename: string
objectId: number
},
first = 1,
) {
const data = (await new Client()
.prepareQuery({
query: gql`
query ($first: Int!) {
events(first: $first) {
nodes {
__typename
objectId
}
}
}
`,
variables: { first },
})
.getData()) as { events: { nodes: unknown[] } }

expect(data.events.nodes).toContainEqual(event)
}

/**
* Assertation that no error events have been triggert to sentry
*/
Expand Down
1 change: 1 addition & 0 deletions __tests__/__utils__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as R from 'ramda'
export * from './assertions'
export * from './handlers'
export * from './services'
export * from './query'

export function getTypenameAndId(value: { __typename: string; id: number }) {
return R.pick(['__typename', 'id'], value)
Expand Down
52 changes: 52 additions & 0 deletions __tests__/__utils__/query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import gql from 'graphql-tag'

import { Client } from './assertions'

export const taxonomyTermQuery = new Client().prepareQuery({
query: gql`
query ($id: Int!) {
uuid(id: $id) {
__typename
... on TaxonomyTerm {
id
trashed
type
instance
alias
title
name
description
weight
taxonomyId
path {
id
}
parent {
id
}
children {
nodes {
id
}
}
}
}
}
`,
})

export const subjectQuery = new Client().prepareQuery({
query: gql`
query ($instance: Instance!) {
subject {
subjects(instance: $instance) {
id
taxonomyTerm {
name
}
}
}
}
`,
variables: { instance: 'de' },
})
2 changes: 1 addition & 1 deletion __tests__/schema/entity/checkout-revision.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import {
articleRevision,
user as baseUser,
taxonomyTermSubject,
emptySubjects,
} from '../../../__fixtures__'
import { getTypenameAndId, nextUuid, given, Client } from '../../__utils__'
import { emptySubjects } from '../subject'
import { Instance } from '~/types'

const user = { ...baseUser, roles: ['de_reviewer'] }
Expand Down
2 changes: 1 addition & 1 deletion __tests__/schema/entity/reject-revision.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import {
articleRevision,
taxonomyTermSubject,
user as baseUser,
emptySubjects,
} from '../../../__fixtures__'
import { given, getTypenameAndId, nextUuid, Client } from '../../__utils__'
import { emptySubjects } from '../subject'
import { Instance } from '~/types'

const user = { ...baseUser, roles: ['de_reviewer'] }
Expand Down
7 changes: 2 additions & 5 deletions __tests__/schema/entity/set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -322,11 +322,8 @@ testCases.forEach((testCase) => {
await mutationWithEntityId.shouldFailWithError('INTERNAL_SERVER_ERROR')
})

test('fails when parent does not exists', async () => {
given('UuidQuery')
.withPayload({ id: testCase.parent.id })
.returnsNotFound()

// TODO: Make it a proper test when doing the migration
test.skip('fails when parent does not exists', async () => {
await mutationWithParentId.shouldFailWithError('BAD_USER_INPUT')
})

Expand Down
64 changes: 8 additions & 56 deletions __tests__/schema/subject.ts
Original file line number Diff line number Diff line change
@@ -1,66 +1,18 @@
import gql from 'graphql-tag'

import { article, taxonomyTermSubject } from '../../__fixtures__'
import { Client, given } from '../__utils__'
import { Instance } from '~/types'

export const emptySubjects = [
{ unrevisedEntities: { nodes: [] } },
{ unrevisedEntities: { nodes: [] } },
{ unrevisedEntities: { nodes: [] } },
{ unrevisedEntities: { nodes: [] } },
{ unrevisedEntities: { nodes: [] } },
{ unrevisedEntities: { nodes: [] } },
{ unrevisedEntities: { nodes: [] } },
{ unrevisedEntities: { nodes: [] } },
]
import { article, emptySubjects, taxonomyTermSubject } from '../../__fixtures__'
import { Client, given, subjectQuery } from '../__utils__'

test('endpoint "subjects" returns list of all subjects for an instance', async () => {
given('UuidQuery').for(taxonomyTermSubject)

await new Client()
.prepareQuery({
query: gql`
query ($instance: Instance!) {
subject {
subjects(instance: $instance) {
taxonomyTerm {
name
}
}
}
}
`,
})
.withVariables({ instance: Instance.En })
.shouldReturnData({
subject: {
subjects: [{ taxonomyTerm: { name: 'Math' } }],
},
})
await subjectQuery.withVariables({ instance: 'en' }).shouldReturnData({
subject: { subjects: [{ taxonomyTerm: { name: 'Math' } }] },
})
})

test('`Subject.id` returns encoded id of subject', async () => {
given('UuidQuery').for(taxonomyTermSubject)

await new Client()
.prepareQuery({
query: gql`
query ($instance: Instance!) {
subject {
subjects(instance: $instance) {
id
}
}
}
`,
})
.withVariables({ instance: Instance.En })
.shouldReturnData({
subject: {
subjects: [{ id: 'czIzNTkz' }],
},
})
await subjectQuery.withVariables({ instance: 'en' }).shouldReturnData({
subject: { subjects: [{ id: 'czIzNTkz' }] },
})
})

test('`Subject.unrevisedEntities` returns list of unrevisedEntities', async () => {
Expand Down
Loading

0 comments on commit 6490a91

Please sign in to comment.