Skip to content

Commit

Permalink
Add e2e tests for external DB and file-store configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
Szymongib committed Feb 4, 2022
1 parent cc42f19 commit 00ef7f0
Show file tree
Hide file tree
Showing 13 changed files with 587 additions and 48 deletions.
95 changes: 95 additions & 0 deletions resources/minio.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# This file contains MinIO manifest than can be applied locally in the cluster and
# treated as an external file store for Mattermost instance.
# This manifest is prepared for development and testing purposes and should not be used in production environment.

---
kind: Deployment
apiVersion: apps/v1
metadata:
name: minio
labels:
app: minio
spec:
replicas: 1
selector:
matchLabels:
app: minio
template:
metadata:
labels:
app: minio
spec:
containers:
- name: minio
image: minio/minio:RELEASE.2021-10-27T16-29-42Z
args: ['server', '/data', '--console-address', ':9001']
ports:
- name: minio
containerPort: 9000
volumeMounts:
- name: s3-pv-storage
mountPath: /data
env:
- name: MINIO_SERVER_URL
value: https://minio.example.com
- name: MINIO_BROWSER_REDIRECT_URL
value: https://console.minio.example.com
- name: MINIO_IDENTITY_OPENID_CONFIG_URL
value: https://keycloak.example.com/auth/realms/home/.well-known/openid-configuration
- name: MINIO_IDENTITY_OPENID_CLIENT_ID
value: minio
- name: MINIO_IDENTITY_OPENID_CLIENT_SECRET
value: secret
- name: MINIO_ROOT_USER
valueFrom:
secretKeyRef:
name: minio
key: MINIO_ROOT_USER
- name: MINIO_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: minio
key: MINIO_ROOT_PASSWORD
volumes:
- name: s3-pv-storage
hostPath:
path: /minio-data
---

apiVersion: v1
kind: Service
metadata:
name: minio
spec:
ports:
- protocol: TCP
name: minio
port: 9000
- protocol: TCP
name: minio-console
port: 9001
selector:
app: minio
---

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: s3-pvc
spec:
storageClassName: local-path
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Secret
metadata:
name: minio
labels:
app: minio
data:
MINIO_ROOT_USER: bXktYWNjZXNzLWtleQ==
MINIO_ROOT_PASSWORD: bXlYWFh4eHgvc2VjcmV0WFhYWHh4eC9rZXlYWHh4eA==
19 changes: 19 additions & 0 deletions resources/mm-secrets.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Secrets that can be referenced in Mattermost CR.

apiVersion: v1
data:
DB_CONNECTION_STRING: cG9zdGdyZXM6Ly9wb3N0Z3JlczpwYXNzd29yZEBwb3N0Z3Jlc3FsOjU0MzIvcG9zdGdyZXM/c3NsbW9kZT1kaXNhYmxl
kind: Secret
metadata:
name: db-credentials
type: Opaque
---

apiVersion: v1
kind: Secret
metadata:
name: file-store-credentials
type: Opaque
data:
accesskey: bXktYWNjZXNzLWtleQ==
secretkey: bXlYWFh4eHgvc2VjcmV0WFhYWHh4eC9rZXlYWHh4eA==
86 changes: 86 additions & 0 deletions resources/postgres.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# This file contains Postgres manifest than can be applied locally in the cluster and
# treated as an external database for Mattermost instance.
# This manifest is prepared for development and testing purposes and should not be used in production environment.

---
apiVersion: v1
kind: Service
metadata:
name: postgresql
labels:
app: postgres
tier: postgreSQL
spec:
ports:
- port: 5432
selector:
app: postgres
tier: postgreSQL
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-claim
labels:
app: postgres
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgresql
labels:
app: postgres
spec:
strategy:
type: Recreate
selector:
matchLabels:
app: postgres
tier: postgreSQL
template:
metadata:
labels:
app: postgres
tier: postgreSQL
spec:
containers:
- image: postgres:12-alpine
name: postgresql
env:
- name: POSTGRES_USER
value: postgres
- name: POSTGRES_DB
value: postgres
- name: POSTGRES_PASSWORD
value: password
ports:
- containerPort: 5432
name: postgresql
volumeMounts:
- name: postgresql
mountPath: /var/lib/postgresql/data
volumes:
- name: postgresql
emptyDir: {}

---
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-volume-1
labels:
type: local
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /tmp/data/pv-1
persistentVolumeReclaimPolicy: Recycle
107 changes: 107 additions & 0 deletions test/e2e-external/apply_resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package e2e

import (
"bytes"
"context"
"io/ioutil"

mmv1beta "github.com/mattermost/mattermost-operator/apis/mattermost/v1beta1"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/client"
)

func CreateFromFile(ctx context.Context, k8sClient client.Client, namespace, path string) (func(), error) {
content, err := ioutil.ReadFile(path)
if err != nil {
return func() {}, errors.Wrap(err, "failed to read file content")
}

content = filterCommentsAndEmptyLines(content)
resources := bytes.Split(content, []byte("\n---"))

decoder, err := defaultDecoder()
if err != nil {
return func() {}, errors.Wrap(err, "failed to initialize decoder")
}

objects := []client.Object{}

for _, res := range resources {
if len(res) == 0 {
continue
}

runtimeObject, _, err := decoder.Decode(res, nil, nil)
if err != nil {
return func() {}, errors.Wrap(err, "failed to decode runtimeObject")
}

object, ok := runtimeObject.(client.Object)
if !ok {
return func() {}, errors.New("failed to get runtimeObject metadata")
}

object.SetNamespace(namespace)

err = k8sClient.Create(ctx, object)
if err != nil {
return func() {}, errors.Wrap(err, "failed to apply runtimeObject")
}

objects = append(objects, object)
}

cleanup := func() {
for _, obj := range objects {
_ = k8sClient.Delete(context.Background(), obj)
}
}

return cleanup, nil
}

func filterCommentsAndEmptyLines(fileContent []byte) []byte {
lines := bytes.Split(fileContent, []byte("\n"))

newLines := make([][]byte, 0, len(lines))

for _, l := range lines {
if !bytes.HasPrefix(l, []byte("#")) && len(bytes.TrimSpace(l)) != 0 {
newLines = append(newLines, l)
}
}

return bytes.Join(newLines, []byte("\n"))
}

func defaultScheme() (*runtime.Scheme, error) {
resourcesSchema := runtime.NewScheme()

var addToSchemes = []func(*runtime.Scheme) error{
scheme.AddToScheme,
mmv1beta.AddToScheme,
}

for _, f := range addToSchemes {
err := f(resourcesSchema)
if err != nil {
return nil, errors.Wrap(err, "failed to add types to schema")
}
}

return resourcesSchema, nil
}

func defaultDecoder() (runtime.Decoder, error) {
resourceScheme, err := defaultScheme()
if err != nil {
return nil, err
}
codecs := serializer.NewCodecFactory(resourceScheme)
decoder := codecs.UniversalDeserializer()

return decoder, nil
}
64 changes: 64 additions & 0 deletions test/e2e-external/external_db_filestore_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package e2e

import (
"context"
"testing"
"time"

mmv1beta "github.com/mattermost/mattermost-operator/apis/mattermost/v1beta1"
ptrUtil "github.com/mattermost/mattermost-operator/pkg/utils"
"github.com/mattermost/mattermost-operator/test/e2e"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)

func Test_MattermostExternalServices(t *testing.T) {
namespace := "e2e-test-external-db-file-store"

testEnv, err := SetupTestEnv(k8sClient, namespace)
require.NoError(t, err)
defer testEnv.CleanupFunc()

mattermost := &mmv1beta.Mattermost{
ObjectMeta: metav1.ObjectMeta{
Name: "test-mm",
Namespace: namespace,
},
Spec: mmv1beta.MattermostSpec{
Ingress: &mmv1beta.Ingress{
Host: "e2e-test-example.mattermost.dev",
},
Replicas: ptrUtil.NewInt32(1),
FileStore: mmv1beta.FileStore{
External: &testEnv.FileStoreConfig,
},
Database: mmv1beta.Database{
External: &testEnv.DBConfig,
},
},
}

expectValidMattermostInstance(t, mattermost)
}

func expectValidMattermostInstance(t *testing.T, mattermost *mmv1beta.Mattermost) {
mmNamespaceName := types.NamespacedName{Namespace: mattermost.Namespace, Name: mattermost.Name}

ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()

err := k8sClient.Create(ctx, mattermost)
require.NoError(t, err)
defer func() {
err = k8sClient.Delete(context.Background(), mattermost)
require.NoError(t, err)
}()

err = e2e.WaitForMattermostStable(t, k8sClient, mmNamespaceName, 3*time.Minute)
require.NoError(t, err)

// TODO: Run some basic Mattermost functionality test here
// this most likely needs to be done from inside the cluster
// by running some job.
}
Loading

0 comments on commit 00ef7f0

Please sign in to comment.