You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2023/05/16 14:50:51 UTC

[plc4x] branch develop updated: test(plc4go/spi): add test for DefaultPlcSubscriptionRequest

This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git


The following commit(s) were added to refs/heads/develop by this push:
     new 1c978234e5 test(plc4go/spi): add test for DefaultPlcSubscriptionRequest
1c978234e5 is described below

commit 1c978234e5943219886f195ce5064d197ac7c839
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Tue May 16 16:50:41 2023 +0200

    test(plc4go/spi): add test for DefaultPlcSubscriptionRequest
---
 .../model/DefaultPlcSubscriptionRequest_test.go    | 806 +++++++++++++++++++++
 plc4go/spi/model/mock_PlcSubscriber_test.go        | 226 ++++++
 plc4go/spi/model/mock_requirements.go              |   5 +
 3 files changed, 1037 insertions(+)

diff --git a/plc4go/spi/model/DefaultPlcSubscriptionRequest_test.go b/plc4go/spi/model/DefaultPlcSubscriptionRequest_test.go
new file mode 100644
index 0000000000..66a3556e20
--- /dev/null
+++ b/plc4go/spi/model/DefaultPlcSubscriptionRequest_test.go
@@ -0,0 +1,806 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *   https://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.
+ */
+
+package model
+
+import (
+	"context"
+	"fmt"
+	"github.com/pkg/errors"
+	"github.com/stretchr/testify/mock"
+	"testing"
+	"time"
+
+	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
+	"github.com/apache/plc4x/plc4go/spi"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestDefaultPlcSubscriptionRequestBuilder_AddChangeOfStateTag(t *testing.T) {
+	type fields struct {
+		subscriber             spi.PlcSubscriber
+		tagHandler             spi.PlcTagHandler
+		valueHandler           spi.PlcValueHandler
+		tagNames               []string
+		tagAddresses           map[string]string
+		tags                   map[string]apiModel.PlcTag
+		types                  map[string]SubscriptionType
+		intervals              map[string]time.Duration
+		preRegisteredConsumers map[string][]apiModel.PlcSubscriptionEventConsumer
+	}
+	type args struct {
+		name string
+		tag  apiModel.PlcTag
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   apiModel.PlcSubscriptionRequestBuilder
+	}{
+		{
+			name: "add it",
+			fields: fields{
+				tagAddresses:           map[string]string{},
+				tags:                   map[string]apiModel.PlcTag{},
+				types:                  map[string]SubscriptionType{},
+				intervals:              map[string]time.Duration{},
+				preRegisteredConsumers: map[string][]apiModel.PlcSubscriptionEventConsumer{},
+			},
+			want: &DefaultPlcSubscriptionRequestBuilder{
+				tagNames:               []string{""},
+				tagAddresses:           map[string]string{},
+				tags:                   map[string]apiModel.PlcTag{"": nil},
+				types:                  map[string]SubscriptionType{"": 2},
+				intervals:              map[string]time.Duration{},
+				preRegisteredConsumers: map[string][]apiModel.PlcSubscriptionEventConsumer{},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcSubscriptionRequestBuilder{
+				subscriber:             tt.fields.subscriber,
+				tagHandler:             tt.fields.tagHandler,
+				valueHandler:           tt.fields.valueHandler,
+				tagNames:               tt.fields.tagNames,
+				tagAddresses:           tt.fields.tagAddresses,
+				tags:                   tt.fields.tags,
+				types:                  tt.fields.types,
+				intervals:              tt.fields.intervals,
+				preRegisteredConsumers: tt.fields.preRegisteredConsumers,
+			}
+			assert.Equalf(t, tt.want, d.AddChangeOfStateTag(tt.args.name, tt.args.tag), "AddChangeOfStateTag(%v, %v)", tt.args.name, tt.args.tag)
+		})
+	}
+}
+
+func TestDefaultPlcSubscriptionRequestBuilder_AddChangeOfStateTagAddress(t *testing.T) {
+	type fields struct {
+		subscriber             spi.PlcSubscriber
+		tagHandler             spi.PlcTagHandler
+		valueHandler           spi.PlcValueHandler
+		tagNames               []string
+		tagAddresses           map[string]string
+		tags                   map[string]apiModel.PlcTag
+		types                  map[string]SubscriptionType
+		intervals              map[string]time.Duration
+		preRegisteredConsumers map[string][]apiModel.PlcSubscriptionEventConsumer
+	}
+	type args struct {
+		name       string
+		tagAddress string
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   apiModel.PlcSubscriptionRequestBuilder
+	}{
+		{
+			name: "add it",
+			fields: fields{
+				tagAddresses:           map[string]string{},
+				tags:                   map[string]apiModel.PlcTag{},
+				types:                  map[string]SubscriptionType{},
+				intervals:              map[string]time.Duration{},
+				preRegisteredConsumers: map[string][]apiModel.PlcSubscriptionEventConsumer{},
+			},
+			want: &DefaultPlcSubscriptionRequestBuilder{
+				tagNames:               []string{""},
+				tagAddresses:           map[string]string{"": ""},
+				tags:                   map[string]apiModel.PlcTag{},
+				types:                  map[string]SubscriptionType{"": 2},
+				intervals:              map[string]time.Duration{},
+				preRegisteredConsumers: map[string][]apiModel.PlcSubscriptionEventConsumer{},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcSubscriptionRequestBuilder{
+				subscriber:             tt.fields.subscriber,
+				tagHandler:             tt.fields.tagHandler,
+				valueHandler:           tt.fields.valueHandler,
+				tagNames:               tt.fields.tagNames,
+				tagAddresses:           tt.fields.tagAddresses,
+				tags:                   tt.fields.tags,
+				types:                  tt.fields.types,
+				intervals:              tt.fields.intervals,
+				preRegisteredConsumers: tt.fields.preRegisteredConsumers,
+			}
+			assert.Equalf(t, tt.want, d.AddChangeOfStateTagAddress(tt.args.name, tt.args.tagAddress), "AddChangeOfStateTagAddress(%v, %v)", tt.args.name, tt.args.tagAddress)
+		})
+	}
+}
+
+func TestDefaultPlcSubscriptionRequestBuilder_AddCyclicTag(t *testing.T) {
+	type fields struct {
+		subscriber             spi.PlcSubscriber
+		tagHandler             spi.PlcTagHandler
+		valueHandler           spi.PlcValueHandler
+		tagNames               []string
+		tagAddresses           map[string]string
+		tags                   map[string]apiModel.PlcTag
+		types                  map[string]SubscriptionType
+		intervals              map[string]time.Duration
+		preRegisteredConsumers map[string][]apiModel.PlcSubscriptionEventConsumer
+	}
+	type args struct {
+		name     string
+		tag      apiModel.PlcTag
+		interval time.Duration
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   apiModel.PlcSubscriptionRequestBuilder
+	}{
+		{
+			name: "add it",
+			fields: fields{
+				tagAddresses:           map[string]string{},
+				tags:                   map[string]apiModel.PlcTag{},
+				types:                  map[string]SubscriptionType{},
+				intervals:              map[string]time.Duration{},
+				preRegisteredConsumers: map[string][]apiModel.PlcSubscriptionEventConsumer{},
+			},
+			want: &DefaultPlcSubscriptionRequestBuilder{
+				tagNames:               []string{""},
+				tagAddresses:           map[string]string{},
+				tags:                   map[string]apiModel.PlcTag{"": nil},
+				types:                  map[string]SubscriptionType{"": 1},
+				intervals:              map[string]time.Duration{"": 0},
+				preRegisteredConsumers: map[string][]apiModel.PlcSubscriptionEventConsumer{},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcSubscriptionRequestBuilder{
+				subscriber:             tt.fields.subscriber,
+				tagHandler:             tt.fields.tagHandler,
+				valueHandler:           tt.fields.valueHandler,
+				tagNames:               tt.fields.tagNames,
+				tagAddresses:           tt.fields.tagAddresses,
+				tags:                   tt.fields.tags,
+				types:                  tt.fields.types,
+				intervals:              tt.fields.intervals,
+				preRegisteredConsumers: tt.fields.preRegisteredConsumers,
+			}
+			assert.Equalf(t, tt.want, d.AddCyclicTag(tt.args.name, tt.args.tag, tt.args.interval), "AddCyclicTag(%v, %v, %v)", tt.args.name, tt.args.tag, tt.args.interval)
+		})
+	}
+}
+
+func TestDefaultPlcSubscriptionRequestBuilder_AddCyclicTagAddress(t *testing.T) {
+	type fields struct {
+		subscriber             spi.PlcSubscriber
+		tagHandler             spi.PlcTagHandler
+		valueHandler           spi.PlcValueHandler
+		tagNames               []string
+		tagAddresses           map[string]string
+		tags                   map[string]apiModel.PlcTag
+		types                  map[string]SubscriptionType
+		intervals              map[string]time.Duration
+		preRegisteredConsumers map[string][]apiModel.PlcSubscriptionEventConsumer
+	}
+	type args struct {
+		name       string
+		tagAddress string
+		interval   time.Duration
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   apiModel.PlcSubscriptionRequestBuilder
+	}{
+		{
+			name: "add it",
+			fields: fields{
+				tagAddresses:           map[string]string{},
+				tags:                   map[string]apiModel.PlcTag{},
+				types:                  map[string]SubscriptionType{},
+				intervals:              map[string]time.Duration{},
+				preRegisteredConsumers: map[string][]apiModel.PlcSubscriptionEventConsumer{},
+			},
+			want: &DefaultPlcSubscriptionRequestBuilder{
+				tagNames:               []string{""},
+				tagAddresses:           map[string]string{"": ""},
+				tags:                   map[string]apiModel.PlcTag{},
+				types:                  map[string]SubscriptionType{"": 1},
+				intervals:              map[string]time.Duration{"": 0},
+				preRegisteredConsumers: map[string][]apiModel.PlcSubscriptionEventConsumer{},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcSubscriptionRequestBuilder{
+				subscriber:             tt.fields.subscriber,
+				tagHandler:             tt.fields.tagHandler,
+				valueHandler:           tt.fields.valueHandler,
+				tagNames:               tt.fields.tagNames,
+				tagAddresses:           tt.fields.tagAddresses,
+				tags:                   tt.fields.tags,
+				types:                  tt.fields.types,
+				intervals:              tt.fields.intervals,
+				preRegisteredConsumers: tt.fields.preRegisteredConsumers,
+			}
+			assert.Equalf(t, tt.want, d.AddCyclicTagAddress(tt.args.name, tt.args.tagAddress, tt.args.interval), "AddCyclicTagAddress(%v, %v, %v)", tt.args.name, tt.args.tagAddress, tt.args.interval)
+		})
+	}
+}
+
+func TestDefaultPlcSubscriptionRequestBuilder_AddEventTag(t *testing.T) {
+	type fields struct {
+		subscriber             spi.PlcSubscriber
+		tagHandler             spi.PlcTagHandler
+		valueHandler           spi.PlcValueHandler
+		tagNames               []string
+		tagAddresses           map[string]string
+		tags                   map[string]apiModel.PlcTag
+		types                  map[string]SubscriptionType
+		intervals              map[string]time.Duration
+		preRegisteredConsumers map[string][]apiModel.PlcSubscriptionEventConsumer
+	}
+	type args struct {
+		name string
+		tag  apiModel.PlcTag
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   apiModel.PlcSubscriptionRequestBuilder
+	}{
+		{
+			name: "add it",
+			fields: fields{
+				tagAddresses:           map[string]string{},
+				tags:                   map[string]apiModel.PlcTag{},
+				types:                  map[string]SubscriptionType{},
+				intervals:              map[string]time.Duration{},
+				preRegisteredConsumers: map[string][]apiModel.PlcSubscriptionEventConsumer{},
+			},
+			want: &DefaultPlcSubscriptionRequestBuilder{
+				tagNames:               []string{""},
+				tagAddresses:           map[string]string{},
+				tags:                   map[string]apiModel.PlcTag{"": nil},
+				types:                  map[string]SubscriptionType{"": 3},
+				intervals:              map[string]time.Duration{},
+				preRegisteredConsumers: map[string][]apiModel.PlcSubscriptionEventConsumer{},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcSubscriptionRequestBuilder{
+				subscriber:             tt.fields.subscriber,
+				tagHandler:             tt.fields.tagHandler,
+				valueHandler:           tt.fields.valueHandler,
+				tagNames:               tt.fields.tagNames,
+				tagAddresses:           tt.fields.tagAddresses,
+				tags:                   tt.fields.tags,
+				types:                  tt.fields.types,
+				intervals:              tt.fields.intervals,
+				preRegisteredConsumers: tt.fields.preRegisteredConsumers,
+			}
+			assert.Equalf(t, tt.want, d.AddEventTag(tt.args.name, tt.args.tag), "AddEventTag(%v, %v)", tt.args.name, tt.args.tag)
+		})
+	}
+}
+
+func TestDefaultPlcSubscriptionRequestBuilder_AddEventTagAddress(t *testing.T) {
+	type fields struct {
+		subscriber             spi.PlcSubscriber
+		tagHandler             spi.PlcTagHandler
+		valueHandler           spi.PlcValueHandler
+		tagNames               []string
+		tagAddresses           map[string]string
+		tags                   map[string]apiModel.PlcTag
+		types                  map[string]SubscriptionType
+		intervals              map[string]time.Duration
+		preRegisteredConsumers map[string][]apiModel.PlcSubscriptionEventConsumer
+	}
+	type args struct {
+		name       string
+		tagAddress string
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   apiModel.PlcSubscriptionRequestBuilder
+	}{
+		{
+			name: "add it",
+			fields: fields{
+				tagAddresses:           map[string]string{},
+				tags:                   map[string]apiModel.PlcTag{},
+				types:                  map[string]SubscriptionType{},
+				intervals:              map[string]time.Duration{},
+				preRegisteredConsumers: map[string][]apiModel.PlcSubscriptionEventConsumer{},
+			},
+			want: &DefaultPlcSubscriptionRequestBuilder{
+				tagNames:               []string{""},
+				tagAddresses:           map[string]string{"": ""},
+				tags:                   map[string]apiModel.PlcTag{},
+				types:                  map[string]SubscriptionType{"": 3},
+				intervals:              map[string]time.Duration{},
+				preRegisteredConsumers: map[string][]apiModel.PlcSubscriptionEventConsumer{},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcSubscriptionRequestBuilder{
+				subscriber:             tt.fields.subscriber,
+				tagHandler:             tt.fields.tagHandler,
+				valueHandler:           tt.fields.valueHandler,
+				tagNames:               tt.fields.tagNames,
+				tagAddresses:           tt.fields.tagAddresses,
+				tags:                   tt.fields.tags,
+				types:                  tt.fields.types,
+				intervals:              tt.fields.intervals,
+				preRegisteredConsumers: tt.fields.preRegisteredConsumers,
+			}
+			assert.Equalf(t, tt.want, d.AddEventTagAddress(tt.args.name, tt.args.tagAddress), "AddEventTagAddress(%v, %v)", tt.args.name, tt.args.tagAddress)
+		})
+	}
+}
+
+func TestDefaultPlcSubscriptionRequestBuilder_AddPreRegisteredConsumer(t *testing.T) {
+	type fields struct {
+		subscriber             spi.PlcSubscriber
+		tagHandler             spi.PlcTagHandler
+		valueHandler           spi.PlcValueHandler
+		tagNames               []string
+		tagAddresses           map[string]string
+		tags                   map[string]apiModel.PlcTag
+		types                  map[string]SubscriptionType
+		intervals              map[string]time.Duration
+		preRegisteredConsumers map[string][]apiModel.PlcSubscriptionEventConsumer
+	}
+	type args struct {
+		name     string
+		consumer apiModel.PlcSubscriptionEventConsumer
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   apiModel.PlcSubscriptionRequestBuilder
+	}{
+		{
+			name: "add it",
+			fields: fields{
+				preRegisteredConsumers: map[string][]apiModel.PlcSubscriptionEventConsumer{},
+			},
+			want: &DefaultPlcSubscriptionRequestBuilder{
+				preRegisteredConsumers: map[string][]apiModel.PlcSubscriptionEventConsumer{
+					"": {func() apiModel.PlcSubscriptionEventConsumer { return nil }()},
+				},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcSubscriptionRequestBuilder{
+				subscriber:             tt.fields.subscriber,
+				tagHandler:             tt.fields.tagHandler,
+				valueHandler:           tt.fields.valueHandler,
+				tagNames:               tt.fields.tagNames,
+				tagAddresses:           tt.fields.tagAddresses,
+				tags:                   tt.fields.tags,
+				types:                  tt.fields.types,
+				intervals:              tt.fields.intervals,
+				preRegisteredConsumers: tt.fields.preRegisteredConsumers,
+			}
+			assert.Equalf(t, tt.want, d.AddPreRegisteredConsumer(tt.args.name, tt.args.consumer), "AddPreRegisteredConsumer(%v, %v)", tt.args.name, tt.args.consumer)
+		})
+	}
+}
+
+func TestDefaultPlcSubscriptionRequestBuilder_Build(t *testing.T) {
+	type fields struct {
+		subscriber             spi.PlcSubscriber
+		tagHandler             spi.PlcTagHandler
+		valueHandler           spi.PlcValueHandler
+		tagNames               []string
+		tagAddresses           map[string]string
+		tags                   map[string]apiModel.PlcTag
+		types                  map[string]SubscriptionType
+		intervals              map[string]time.Duration
+		preRegisteredConsumers map[string][]apiModel.PlcSubscriptionEventConsumer
+	}
+	tests := []struct {
+		name      string
+		fields    fields
+		mockSetup func(t *testing.T, fields *fields)
+		want      apiModel.PlcSubscriptionRequest
+		wantErr   assert.ErrorAssertionFunc
+	}{
+		{
+			name: "build it",
+			want: &DefaultPlcSubscriptionRequest{
+				DefaultPlcTagRequest: NewDefaultPlcTagRequest(nil, nil),
+			},
+			wantErr: assert.NoError,
+		},
+		{
+			name: "build it (with addresses)",
+			fields: fields{
+				tagNames:     []string{"a"},
+				tagAddresses: map[string]string{"a": ""},
+				tags:         map[string]apiModel.PlcTag{},
+			},
+			mockSetup: func(t *testing.T, fields *fields) {
+				handler := NewMockPlcTagHandler(t)
+				handler.EXPECT().ParseTag(mock.Anything).Return(nil, nil)
+				fields.tagHandler = handler
+			},
+			want: &DefaultPlcSubscriptionRequest{
+				DefaultPlcTagRequest: NewDefaultPlcTagRequest(map[string]apiModel.PlcTag{"a": nil}, []string{"a"}),
+			},
+			wantErr: assert.NoError,
+		},
+		{
+			name: "build it (with addresses failing)",
+			fields: fields{
+				tagNames:     []string{"a"},
+				tagAddresses: map[string]string{"a": ""},
+				tags:         map[string]apiModel.PlcTag{},
+			},
+			mockSetup: func(t *testing.T, fields *fields) {
+				handler := NewMockPlcTagHandler(t)
+				handler.EXPECT().ParseTag(mock.Anything).Return(nil, errors.New("nope"))
+				fields.tagHandler = handler
+			},
+			wantErr: assert.Error,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if tt.mockSetup != nil {
+				tt.mockSetup(t, &tt.fields)
+			}
+			d := &DefaultPlcSubscriptionRequestBuilder{
+				subscriber:             tt.fields.subscriber,
+				tagHandler:             tt.fields.tagHandler,
+				valueHandler:           tt.fields.valueHandler,
+				tagNames:               tt.fields.tagNames,
+				tagAddresses:           tt.fields.tagAddresses,
+				tags:                   tt.fields.tags,
+				types:                  tt.fields.types,
+				intervals:              tt.fields.intervals,
+				preRegisteredConsumers: tt.fields.preRegisteredConsumers,
+			}
+			got, err := d.Build()
+			if !tt.wantErr(t, err, fmt.Sprintf("Build()")) {
+				return
+			}
+			assert.Equalf(t, tt.want, got, "Build()")
+		})
+	}
+}
+
+func TestDefaultPlcSubscriptionRequest_Execute(t *testing.T) {
+	type fields struct {
+		DefaultPlcTagRequest   *DefaultPlcTagRequest
+		types                  map[string]SubscriptionType
+		intervals              map[string]time.Duration
+		preRegisteredConsumers map[string][]apiModel.PlcSubscriptionEventConsumer
+		subscriber             spi.PlcSubscriber
+	}
+	tests := []struct {
+		name      string
+		fields    fields
+		mockSetup func(t *testing.T, fields *fields)
+		want      <-chan apiModel.PlcSubscriptionRequestResult
+	}{
+		{
+			name: "execute it",
+			mockSetup: func(t *testing.T, fields *fields) {
+				subscriber := NewMockPlcSubscriber(t)
+				subscriber.EXPECT().Subscribe(mock.Anything, mock.Anything).Return(nil)
+				fields.subscriber = subscriber
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if tt.mockSetup != nil {
+				tt.mockSetup(t, &tt.fields)
+			}
+			d := &DefaultPlcSubscriptionRequest{
+				DefaultPlcTagRequest:   tt.fields.DefaultPlcTagRequest,
+				types:                  tt.fields.types,
+				intervals:              tt.fields.intervals,
+				preRegisteredConsumers: tt.fields.preRegisteredConsumers,
+				subscriber:             tt.fields.subscriber,
+			}
+			assert.Equalf(t, tt.want, d.Execute(), "Execute()")
+		})
+	}
+}
+
+func TestDefaultPlcSubscriptionRequest_ExecuteWithContext(t *testing.T) {
+	type fields struct {
+		DefaultPlcTagRequest   *DefaultPlcTagRequest
+		types                  map[string]SubscriptionType
+		intervals              map[string]time.Duration
+		preRegisteredConsumers map[string][]apiModel.PlcSubscriptionEventConsumer
+		subscriber             spi.PlcSubscriber
+	}
+	type args struct {
+		ctx context.Context
+	}
+	tests := []struct {
+		name      string
+		fields    fields
+		args      args
+		mockSetup func(t *testing.T, fields *fields)
+		want      <-chan apiModel.PlcSubscriptionRequestResult
+	}{
+		{
+			name: "execute it",
+			mockSetup: func(t *testing.T, fields *fields) {
+				subscriber := NewMockPlcSubscriber(t)
+				subscriber.EXPECT().Subscribe(mock.Anything, mock.Anything).Return(nil)
+				fields.subscriber = subscriber
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if tt.mockSetup != nil {
+				tt.mockSetup(t, &tt.fields)
+			}
+			d := &DefaultPlcSubscriptionRequest{
+				DefaultPlcTagRequest:   tt.fields.DefaultPlcTagRequest,
+				types:                  tt.fields.types,
+				intervals:              tt.fields.intervals,
+				preRegisteredConsumers: tt.fields.preRegisteredConsumers,
+				subscriber:             tt.fields.subscriber,
+			}
+			assert.Equalf(t, tt.want, d.ExecuteWithContext(tt.args.ctx), "ExecuteWithContext(%v)", tt.args.ctx)
+		})
+	}
+}
+
+func TestDefaultPlcSubscriptionRequest_GetInterval(t *testing.T) {
+	type fields struct {
+		DefaultPlcTagRequest   *DefaultPlcTagRequest
+		types                  map[string]SubscriptionType
+		intervals              map[string]time.Duration
+		preRegisteredConsumers map[string][]apiModel.PlcSubscriptionEventConsumer
+		subscriber             spi.PlcSubscriber
+	}
+	type args struct {
+		name string
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   time.Duration
+	}{
+		{
+			name: "get it",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcSubscriptionRequest{
+				DefaultPlcTagRequest:   tt.fields.DefaultPlcTagRequest,
+				types:                  tt.fields.types,
+				intervals:              tt.fields.intervals,
+				preRegisteredConsumers: tt.fields.preRegisteredConsumers,
+				subscriber:             tt.fields.subscriber,
+			}
+			assert.Equalf(t, tt.want, d.GetInterval(tt.args.name), "GetInterval(%v)", tt.args.name)
+		})
+	}
+}
+
+func TestDefaultPlcSubscriptionRequest_GetPreRegisteredConsumers(t *testing.T) {
+	type fields struct {
+		DefaultPlcTagRequest   *DefaultPlcTagRequest
+		types                  map[string]SubscriptionType
+		intervals              map[string]time.Duration
+		preRegisteredConsumers map[string][]apiModel.PlcSubscriptionEventConsumer
+		subscriber             spi.PlcSubscriber
+	}
+	type args struct {
+		name string
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   []apiModel.PlcSubscriptionEventConsumer
+	}{
+		{
+			name: "get it",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcSubscriptionRequest{
+				DefaultPlcTagRequest:   tt.fields.DefaultPlcTagRequest,
+				types:                  tt.fields.types,
+				intervals:              tt.fields.intervals,
+				preRegisteredConsumers: tt.fields.preRegisteredConsumers,
+				subscriber:             tt.fields.subscriber,
+			}
+			assert.Equalf(t, tt.want, d.GetPreRegisteredConsumers(tt.args.name), "GetPreRegisteredConsumers(%v)", tt.args.name)
+		})
+	}
+}
+
+func TestDefaultPlcSubscriptionRequest_GetType(t *testing.T) {
+	type fields struct {
+		DefaultPlcTagRequest   *DefaultPlcTagRequest
+		types                  map[string]SubscriptionType
+		intervals              map[string]time.Duration
+		preRegisteredConsumers map[string][]apiModel.PlcSubscriptionEventConsumer
+		subscriber             spi.PlcSubscriber
+	}
+	type args struct {
+		name string
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   SubscriptionType
+	}{
+		{
+			name: "get it",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcSubscriptionRequest{
+				DefaultPlcTagRequest:   tt.fields.DefaultPlcTagRequest,
+				types:                  tt.fields.types,
+				intervals:              tt.fields.intervals,
+				preRegisteredConsumers: tt.fields.preRegisteredConsumers,
+				subscriber:             tt.fields.subscriber,
+			}
+			assert.Equalf(t, tt.want, d.GetType(tt.args.name), "GetType(%v)", tt.args.name)
+		})
+	}
+}
+
+func TestNewDefaultPlcSubscriptionRequest(t *testing.T) {
+	type args struct {
+		subscriber             spi.PlcSubscriber
+		tagNames               []string
+		tags                   map[string]apiModel.PlcTag
+		types                  map[string]SubscriptionType
+		intervals              map[string]time.Duration
+		preRegisteredConsumers map[string][]apiModel.PlcSubscriptionEventConsumer
+	}
+	tests := []struct {
+		name string
+		args args
+		want apiModel.PlcSubscriptionRequest
+	}{
+		{
+			name: "create it",
+			want: &DefaultPlcSubscriptionRequest{
+				DefaultPlcTagRequest: NewDefaultPlcTagRequest(nil, nil),
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			assert.Equalf(t, tt.want, NewDefaultPlcSubscriptionRequest(tt.args.subscriber, tt.args.tagNames, tt.args.tags, tt.args.types, tt.args.intervals, tt.args.preRegisteredConsumers), "NewDefaultPlcSubscriptionRequest(%v, %v, %v, %v, %v, %v)", tt.args.subscriber, tt.args.tagNames, tt.args.tags, tt.args.types, tt.args.intervals, tt.args.preRegisteredConsumers)
+		})
+	}
+}
+
+func TestNewDefaultPlcSubscriptionRequestBuilder(t *testing.T) {
+	type args struct {
+		tagHandler   spi.PlcTagHandler
+		valueHandler spi.PlcValueHandler
+		subscriber   spi.PlcSubscriber
+	}
+	tests := []struct {
+		name string
+		args args
+		want apiModel.PlcSubscriptionRequestBuilder
+	}{
+		{
+			name: "create it",
+			want: &DefaultPlcSubscriptionRequestBuilder{
+				tagNames:               []string{},
+				tagAddresses:           map[string]string{},
+				tags:                   map[string]apiModel.PlcTag{},
+				types:                  map[string]SubscriptionType{},
+				intervals:              map[string]time.Duration{},
+				preRegisteredConsumers: map[string][]apiModel.PlcSubscriptionEventConsumer{},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			assert.Equalf(t, tt.want, NewDefaultPlcSubscriptionRequestBuilder(tt.args.tagHandler, tt.args.valueHandler, tt.args.subscriber), "NewDefaultPlcSubscriptionRequestBuilder(%v, %v, %v)", tt.args.tagHandler, tt.args.valueHandler, tt.args.subscriber)
+		})
+	}
+}
+
+func TestSubscriptionType_String(t *testing.T) {
+	tests := []struct {
+		name string
+		s    SubscriptionType
+		want string
+	}{
+		{
+			name: "SubscriptionCyclic",
+			s:    SubscriptionCyclic,
+			want: "SubscriptionCyclic",
+		},
+		{
+			name: "SubscriptionChangeOfState",
+			s:    SubscriptionChangeOfState,
+			want: "SubscriptionChangeOfState",
+		},
+		{
+			name: "SubscriptionEvent",
+			s:    SubscriptionEvent,
+			want: "SubscriptionEvent",
+		},
+		{
+			name: "Unknown",
+			s:    255,
+			want: "Unknown",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			assert.Equalf(t, tt.want, tt.s.String(), "String()")
+		})
+	}
+}
diff --git a/plc4go/spi/model/mock_PlcSubscriber_test.go b/plc4go/spi/model/mock_PlcSubscriber_test.go
new file mode 100644
index 0000000000..57d6f316db
--- /dev/null
+++ b/plc4go/spi/model/mock_PlcSubscriber_test.go
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *   https://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.
+ */
+
+// Code generated by mockery v2.27.1. DO NOT EDIT.
+
+package model
+
+import (
+	context "context"
+
+	apimodel "github.com/apache/plc4x/plc4go/pkg/api/model"
+
+	mock "github.com/stretchr/testify/mock"
+)
+
+// MockPlcSubscriber is an autogenerated mock type for the PlcSubscriber type
+type MockPlcSubscriber struct {
+	mock.Mock
+}
+
+type MockPlcSubscriber_Expecter struct {
+	mock *mock.Mock
+}
+
+func (_m *MockPlcSubscriber) EXPECT() *MockPlcSubscriber_Expecter {
+	return &MockPlcSubscriber_Expecter{mock: &_m.Mock}
+}
+
+// Register provides a mock function with given fields: consumer, handles
+func (_m *MockPlcSubscriber) Register(consumer apimodel.PlcSubscriptionEventConsumer, handles []apimodel.PlcSubscriptionHandle) apimodel.PlcConsumerRegistration {
+	ret := _m.Called(consumer, handles)
+
+	var r0 apimodel.PlcConsumerRegistration
+	if rf, ok := ret.Get(0).(func(apimodel.PlcSubscriptionEventConsumer, []apimodel.PlcSubscriptionHandle) apimodel.PlcConsumerRegistration); ok {
+		r0 = rf(consumer, handles)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(apimodel.PlcConsumerRegistration)
+		}
+	}
+
+	return r0
+}
+
+// MockPlcSubscriber_Register_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Register'
+type MockPlcSubscriber_Register_Call struct {
+	*mock.Call
+}
+
+// Register is a helper method to define mock.On call
+//   - consumer apimodel.PlcSubscriptionEventConsumer
+//   - handles []apimodel.PlcSubscriptionHandle
+func (_e *MockPlcSubscriber_Expecter) Register(consumer interface{}, handles interface{}) *MockPlcSubscriber_Register_Call {
+	return &MockPlcSubscriber_Register_Call{Call: _e.mock.On("Register", consumer, handles)}
+}
+
+func (_c *MockPlcSubscriber_Register_Call) Run(run func(consumer apimodel.PlcSubscriptionEventConsumer, handles []apimodel.PlcSubscriptionHandle)) *MockPlcSubscriber_Register_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(apimodel.PlcSubscriptionEventConsumer), args[1].([]apimodel.PlcSubscriptionHandle))
+	})
+	return _c
+}
+
+func (_c *MockPlcSubscriber_Register_Call) Return(_a0 apimodel.PlcConsumerRegistration) *MockPlcSubscriber_Register_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *MockPlcSubscriber_Register_Call) RunAndReturn(run func(apimodel.PlcSubscriptionEventConsumer, []apimodel.PlcSubscriptionHandle) apimodel.PlcConsumerRegistration) *MockPlcSubscriber_Register_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// Subscribe provides a mock function with given fields: ctx, subscriptionRequest
+func (_m *MockPlcSubscriber) Subscribe(ctx context.Context, subscriptionRequest apimodel.PlcSubscriptionRequest) <-chan apimodel.PlcSubscriptionRequestResult {
+	ret := _m.Called(ctx, subscriptionRequest)
+
+	var r0 <-chan apimodel.PlcSubscriptionRequestResult
+	if rf, ok := ret.Get(0).(func(context.Context, apimodel.PlcSubscriptionRequest) <-chan apimodel.PlcSubscriptionRequestResult); ok {
+		r0 = rf(ctx, subscriptionRequest)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(<-chan apimodel.PlcSubscriptionRequestResult)
+		}
+	}
+
+	return r0
+}
+
+// MockPlcSubscriber_Subscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Subscribe'
+type MockPlcSubscriber_Subscribe_Call struct {
+	*mock.Call
+}
+
+// Subscribe is a helper method to define mock.On call
+//   - ctx context.Context
+//   - subscriptionRequest apimodel.PlcSubscriptionRequest
+func (_e *MockPlcSubscriber_Expecter) Subscribe(ctx interface{}, subscriptionRequest interface{}) *MockPlcSubscriber_Subscribe_Call {
+	return &MockPlcSubscriber_Subscribe_Call{Call: _e.mock.On("Subscribe", ctx, subscriptionRequest)}
+}
+
+func (_c *MockPlcSubscriber_Subscribe_Call) Run(run func(ctx context.Context, subscriptionRequest apimodel.PlcSubscriptionRequest)) *MockPlcSubscriber_Subscribe_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(apimodel.PlcSubscriptionRequest))
+	})
+	return _c
+}
+
+func (_c *MockPlcSubscriber_Subscribe_Call) Return(_a0 <-chan apimodel.PlcSubscriptionRequestResult) *MockPlcSubscriber_Subscribe_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *MockPlcSubscriber_Subscribe_Call) RunAndReturn(run func(context.Context, apimodel.PlcSubscriptionRequest) <-chan apimodel.PlcSubscriptionRequestResult) *MockPlcSubscriber_Subscribe_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// Unregister provides a mock function with given fields: registration
+func (_m *MockPlcSubscriber) Unregister(registration apimodel.PlcConsumerRegistration) {
+	_m.Called(registration)
+}
+
+// MockPlcSubscriber_Unregister_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Unregister'
+type MockPlcSubscriber_Unregister_Call struct {
+	*mock.Call
+}
+
+// Unregister is a helper method to define mock.On call
+//   - registration apimodel.PlcConsumerRegistration
+func (_e *MockPlcSubscriber_Expecter) Unregister(registration interface{}) *MockPlcSubscriber_Unregister_Call {
+	return &MockPlcSubscriber_Unregister_Call{Call: _e.mock.On("Unregister", registration)}
+}
+
+func (_c *MockPlcSubscriber_Unregister_Call) Run(run func(registration apimodel.PlcConsumerRegistration)) *MockPlcSubscriber_Unregister_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(apimodel.PlcConsumerRegistration))
+	})
+	return _c
+}
+
+func (_c *MockPlcSubscriber_Unregister_Call) Return() *MockPlcSubscriber_Unregister_Call {
+	_c.Call.Return()
+	return _c
+}
+
+func (_c *MockPlcSubscriber_Unregister_Call) RunAndReturn(run func(apimodel.PlcConsumerRegistration)) *MockPlcSubscriber_Unregister_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// Unsubscribe provides a mock function with given fields: ctx, unsubscriptionRequest
+func (_m *MockPlcSubscriber) Unsubscribe(ctx context.Context, unsubscriptionRequest apimodel.PlcUnsubscriptionRequest) <-chan apimodel.PlcUnsubscriptionRequestResult {
+	ret := _m.Called(ctx, unsubscriptionRequest)
+
+	var r0 <-chan apimodel.PlcUnsubscriptionRequestResult
+	if rf, ok := ret.Get(0).(func(context.Context, apimodel.PlcUnsubscriptionRequest) <-chan apimodel.PlcUnsubscriptionRequestResult); ok {
+		r0 = rf(ctx, unsubscriptionRequest)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(<-chan apimodel.PlcUnsubscriptionRequestResult)
+		}
+	}
+
+	return r0
+}
+
+// MockPlcSubscriber_Unsubscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Unsubscribe'
+type MockPlcSubscriber_Unsubscribe_Call struct {
+	*mock.Call
+}
+
+// Unsubscribe is a helper method to define mock.On call
+//   - ctx context.Context
+//   - unsubscriptionRequest apimodel.PlcUnsubscriptionRequest
+func (_e *MockPlcSubscriber_Expecter) Unsubscribe(ctx interface{}, unsubscriptionRequest interface{}) *MockPlcSubscriber_Unsubscribe_Call {
+	return &MockPlcSubscriber_Unsubscribe_Call{Call: _e.mock.On("Unsubscribe", ctx, unsubscriptionRequest)}
+}
+
+func (_c *MockPlcSubscriber_Unsubscribe_Call) Run(run func(ctx context.Context, unsubscriptionRequest apimodel.PlcUnsubscriptionRequest)) *MockPlcSubscriber_Unsubscribe_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(apimodel.PlcUnsubscriptionRequest))
+	})
+	return _c
+}
+
+func (_c *MockPlcSubscriber_Unsubscribe_Call) Return(_a0 <-chan apimodel.PlcUnsubscriptionRequestResult) *MockPlcSubscriber_Unsubscribe_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *MockPlcSubscriber_Unsubscribe_Call) RunAndReturn(run func(context.Context, apimodel.PlcUnsubscriptionRequest) <-chan apimodel.PlcUnsubscriptionRequestResult) *MockPlcSubscriber_Unsubscribe_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+type mockConstructorTestingTNewMockPlcSubscriber interface {
+	mock.TestingT
+	Cleanup(func())
+}
+
+// NewMockPlcSubscriber creates a new instance of MockPlcSubscriber. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+func NewMockPlcSubscriber(t mockConstructorTestingTNewMockPlcSubscriber) *MockPlcSubscriber {
+	mock := &MockPlcSubscriber{}
+	mock.Mock.Test(t)
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}
diff --git a/plc4go/spi/model/mock_requirements.go b/plc4go/spi/model/mock_requirements.go
index 2b6934a84f..fdc874b6a2 100644
--- a/plc4go/spi/model/mock_requirements.go
+++ b/plc4go/spi/model/mock_requirements.go
@@ -42,6 +42,11 @@ type PlcWriter interface {
 	spi.PlcWriter
 }
 
+// Deprecated: don't use it in productive code
+type PlcSubscriber interface {
+	spi.PlcSubscriber
+}
+
 // Deprecated: don't use it in productive code
 type PlcTagHandler interface {
 	spi.PlcTagHandler