Skip to content

Commit

Permalink
Add initial node support TCK implementation (cloudstateio#503)
Browse files Browse the repository at this point in the history
  • Loading branch information
pvlugter authored and jroper committed Jan 18, 2021
1 parent 630c9e1 commit faf180b
Show file tree
Hide file tree
Showing 21 changed files with 7,079 additions and 73 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ jobs:
before_script:
- sbt update
- cd node-support && nvm install && nvm use && npm install && cd -
- cd samples/js-shopping-cart && nvm install && nvm use && npm install && cd -
- cd node-support/tck && nvm install && nvm use && npm install && cd -
script:
- sbt 'set concurrentRestrictions in Global += Tags.limitAll(1)' tck/it:test

Expand Down
2 changes: 2 additions & 0 deletions cloudstate-operator/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package main

import (
"flag"
"github.com/cloudstateio/cloudstate/cloudstate-operator/pkg/listeners"
"os"
"time"

Expand Down Expand Up @@ -150,6 +151,7 @@ func main() {
ReconcileTimeout: reconcileTimeout,
OperatorConfig: cfg,
Stores: store,
Listener: &listeners.NullStatefulServiceListener{},
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "StatefulService")
os.Exit(1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"context"
"errors"
"fmt"
"github.com/cloudstateio/cloudstate/cloudstate-operator/pkg/listeners"
"time"

"github.com/cloudstateio/cloudstate/cloudstate-operator/pkg/config"
Expand Down Expand Up @@ -58,6 +59,7 @@ type StatefulServiceReconciler struct {
ReconcileTimeout time.Duration
OperatorConfig *config.OperatorConfig
Stores stores.Stores
Listener listeners.StatefulServiceListener
}

// +kubebuilder:rbac:groups=cloudstate.io,resources=statefulservices,verbs=get;list;watch;create;update;patch;delete
Expand Down Expand Up @@ -144,6 +146,9 @@ func (r *StatefulServiceReconciler) Reconcile(req ctrl.Request) (ctrl.Result, er
log.Error(err, "Unable to create deployment")
return ctrl.Result{}, err
}
if err := r.Listener.DeploymentCreated(ctx, &service, desired); err != nil {
return ctrl.Result{}, err
}
log.Info("Created deployment")
return ctrl.Result{}, nil
}
Expand All @@ -159,6 +164,10 @@ func (r *StatefulServiceReconciler) Reconcile(req ctrl.Request) (ctrl.Result, er
return ctrl.Result{}, err
}

if err := r.Listener.DeploymentUpdated(ctx, &service, actual, desired); err != nil {
return ctrl.Result{}, err
}

log.Info("Updated deployment")
return ctrl.Result{}, nil
}
Expand Down
2 changes: 2 additions & 0 deletions cloudstate-operator/pkg/controllers/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package controllers
import (
"context"
"fmt"
"github.com/cloudstateio/cloudstate/cloudstate-operator/pkg/listeners"
"path/filepath"
"testing"
"time"
Expand Down Expand Up @@ -166,6 +167,7 @@ func runController(ctx context.Context) chan struct{} {
ReconcileTimeout: 10 * time.Second,
OperatorConfig: operatorConfig,
Stores: multistore,
Listener: &listeners.NullStatefulServiceListener{},
}).SetupWithManager(mgr)
Expect(err).ToNot(HaveOccurred(), "failed to setup statefulservice controller")

Expand Down
25 changes: 25 additions & 0 deletions cloudstate-operator/pkg/listeners/statefulservice_listener.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package listeners

import (
"context"
cloudstate "github.com/cloudstateio/cloudstate/cloudstate-operator/pkg/apis/v1alpha1"
appsv1 "k8s.io/api/apps/v1"
)

type StatefulServiceListener interface {
DeploymentCreated(ctx context.Context, service *cloudstate.StatefulService, created *appsv1.Deployment) error
DeploymentUpdated(ctx context.Context, service *cloudstate.StatefulService, old *appsv1.Deployment, new *appsv1.Deployment) error
}

type NullStatefulServiceListener struct {
}

var _ StatefulServiceListener = (*NullStatefulServiceListener)(nil)

func (n *NullStatefulServiceListener) DeploymentCreated(ctx context.Context, service *cloudstate.StatefulService, created *appsv1.Deployment) error {
return nil
}

func (n *NullStatefulServiceListener) DeploymentUpdated(ctx context.Context, service *cloudstate.StatefulService, old *appsv1.Deployment, new *appsv1.Deployment) error {
return nil
}
4 changes: 3 additions & 1 deletion node-support/src/cloudstate.js
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,9 @@ class CloudState {
serviceVersion: this.options.serviceVersion,
serviceRuntime: process.title + " " + process.version,
supportLibraryName: packageInfo.name,
supportLibraryVersion: packageInfo.version
supportLibraryVersion: packageInfo.version,
protocolMajorVersion: 0,
protocolMinorVersion: 2
}
});
}
Expand Down
3 changes: 3 additions & 0 deletions node-support/tck/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/node_modules/
/proto/
/user-function.desc
1 change: 1 addition & 0 deletions node-support/tck/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
engine-strict=true
1 change: 1 addition & 0 deletions node-support/tck/.nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v12
87 changes: 87 additions & 0 deletions node-support/tck/eventsourced.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright 2019 Lightbend Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

const EventSourced = require("cloudstate").EventSourced;

const tckModel = new EventSourced(
["proto/eventsourced.proto"],
"cloudstate.tck.model.EventSourcedTckModel",
{
persistenceId: "event-sourced-tck-model",
snapshotEvery: 5
}
);

const Response = tckModel.lookupType("cloudstate.tck.model.Response")
const Persisted = tckModel.lookupType("cloudstate.tck.model.Persisted")

tckModel.initial = entityId => Persisted.create({ value: "" });

tckModel.behavior = state => {
return {
commandHandlers: {
Process: process
},
eventHandlers: {
Persisted: persisted
}
};
};

function process(request, state, context) {
request.actions.forEach(action => {
if (action.emit) {
const event = Persisted.create({ value: action.emit.value });
context.emit(event);
// FIXME: events are not emitted immediately, so we also update the function local state directly for responses
state = persisted(event, state);
} else if (action.forward) {
context.thenForward(two.service.methods.Call, { id: action.forward.id });
} else if (action.effect) {
context.effect(two.service.methods.Call, { id: action.effect.id }, action.effect.synchronous);
} else if (action.fail) {
context.fail(action.fail.message);
}
});
return Response.create(state.value ? { message: state.value } : {});
}

function persisted(event, state) {
state.value += event.value;
return state;
}

const two = new EventSourced(
["proto/eventsourced.proto"],
"cloudstate.tck.model.EventSourcedTwo"
);

two.initial = entityId => Persisted.create({ value: "" });

two.behavior = state => {
return {
commandHandlers: {
Call: call
}
};
};

function call(request) {
return Response.create({});
}

module.exports.tckModel = tckModel;
module.exports.two = two;
22 changes: 22 additions & 0 deletions node-support/tck/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2019 Lightbend Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

const CloudState = require("cloudstate").CloudState;
const server = new CloudState();
const eventSourced = require("./eventsourced.js");
server.addEntity(eventSourced.tckModel);
server.addEntity(eventSourced.two);
server.start();
Loading

0 comments on commit faf180b

Please sign in to comment.