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 13:23:53 UTC

[plc4x] 02/02: test(plc4go/spi): add test for DefaultPlcReadRequest

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

commit f551718d6cf8aba68e5e762452e83bf5a107c3a1
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Tue May 16 15:23:43 2023 +0200

    test(plc4go/spi): add test for DefaultPlcReadRequest
---
 plc4go/spi/model/DefaultPlcReadRequest_test.go     | 590 +++++++++++++++++++++
 plc4go/spi/model/mock_PlcReader_test.go            | 103 ++++
 .../spi/model/mock_ReadRequestInterceptor_test.go  | 149 ++++++
 plc4go/spi/model/mock_requirements.go              |  11 +
 4 files changed, 853 insertions(+)

diff --git a/plc4go/spi/model/DefaultPlcReadRequest_test.go b/plc4go/spi/model/DefaultPlcReadRequest_test.go
new file mode 100644
index 0000000000..b8527c44b9
--- /dev/null
+++ b/plc4go/spi/model/DefaultPlcReadRequest_test.go
@@ -0,0 +1,590 @@
+/*
+ * 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/apache/plc4x/plc4go/spi/utils"
+	"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/apache/plc4x/plc4go/spi/interceptors"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestDefaultPlcReadRequestBuilder_AddTag(t *testing.T) {
+	type fields struct {
+		reader                 spi.PlcReader
+		tagHandler             spi.PlcTagHandler
+		tagNames               []string
+		tagAddresses           map[string]string
+		tags                   map[string]apiModel.PlcTag
+		readRequestInterceptor interceptors.ReadRequestInterceptor
+	}
+	type args struct {
+		name string
+		tag  apiModel.PlcTag
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   apiModel.PlcReadRequestBuilder
+	}{
+		{
+			name: "add it",
+			fields: fields{
+				tagAddresses: map[string]string{},
+				tags:         map[string]apiModel.PlcTag{},
+			},
+			want: &DefaultPlcReadRequestBuilder{
+				tagNames:     []string{""},
+				tagAddresses: map[string]string{},
+				tags:         map[string]apiModel.PlcTag{"": nil},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcReadRequestBuilder{
+				reader:                 tt.fields.reader,
+				tagHandler:             tt.fields.tagHandler,
+				tagNames:               tt.fields.tagNames,
+				tagAddresses:           tt.fields.tagAddresses,
+				tags:                   tt.fields.tags,
+				readRequestInterceptor: tt.fields.readRequestInterceptor,
+			}
+			assert.Equalf(t, tt.want, d.AddTag(tt.args.name, tt.args.tag), "AddTag(%v, %v)", tt.args.name, tt.args.tag)
+		})
+	}
+}
+
+func TestDefaultPlcReadRequestBuilder_AddTagAddress(t *testing.T) {
+	type fields struct {
+		reader                 spi.PlcReader
+		tagHandler             spi.PlcTagHandler
+		tagNames               []string
+		tagAddresses           map[string]string
+		tags                   map[string]apiModel.PlcTag
+		readRequestInterceptor interceptors.ReadRequestInterceptor
+	}
+	type args struct {
+		name  string
+		query string
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   apiModel.PlcReadRequestBuilder
+	}{
+		{
+			name: "add it",
+			fields: fields{
+				tagAddresses: map[string]string{},
+				tags:         map[string]apiModel.PlcTag{},
+			},
+			want: &DefaultPlcReadRequestBuilder{
+				tagNames:     []string{""},
+				tagAddresses: map[string]string{"": ""},
+				tags:         map[string]apiModel.PlcTag{},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcReadRequestBuilder{
+				reader:                 tt.fields.reader,
+				tagHandler:             tt.fields.tagHandler,
+				tagNames:               tt.fields.tagNames,
+				tagAddresses:           tt.fields.tagAddresses,
+				tags:                   tt.fields.tags,
+				readRequestInterceptor: tt.fields.readRequestInterceptor,
+			}
+			assert.Equalf(t, tt.want, d.AddTagAddress(tt.args.name, tt.args.query), "AddTagAddress(%v, %v)", tt.args.name, tt.args.query)
+		})
+	}
+}
+
+func TestDefaultPlcReadRequestBuilder_Build(t *testing.T) {
+	type fields struct {
+		reader                 spi.PlcReader
+		tagHandler             spi.PlcTagHandler
+		tagNames               []string
+		tagAddresses           map[string]string
+		tags                   map[string]apiModel.PlcTag
+		readRequestInterceptor interceptors.ReadRequestInterceptor
+	}
+	tests := []struct {
+		name      string
+		fields    fields
+		mockSetup func(t *testing.T, fields *fields)
+		want      apiModel.PlcReadRequest
+		wantErr   assert.ErrorAssertionFunc
+	}{
+		{
+			name:    "build it",
+			want:    NewDefaultPlcReadRequest(nil, nil, nil, nil),
+			wantErr: assert.NoError,
+		},
+		{
+			name: "build it with tags",
+			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:    NewDefaultPlcReadRequest(map[string]apiModel.PlcTag{"a": nil}, []string{"a"}, nil, nil),
+			wantErr: assert.NoError,
+		},
+		{
+			name: "build it with parse error",
+			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 := &DefaultPlcReadRequestBuilder{
+				reader:                 tt.fields.reader,
+				tagHandler:             tt.fields.tagHandler,
+				tagNames:               tt.fields.tagNames,
+				tagAddresses:           tt.fields.tagAddresses,
+				tags:                   tt.fields.tags,
+				readRequestInterceptor: tt.fields.readRequestInterceptor,
+			}
+			got, err := d.Build()
+			if !tt.wantErr(t, err, fmt.Sprintf("Build()")) {
+				return
+			}
+			assert.Equalf(t, tt.want, got, "Build()")
+		})
+	}
+}
+
+func TestDefaultPlcReadRequest_Execute(t *testing.T) {
+	type fields struct {
+		DefaultPlcTagRequest   *DefaultPlcTagRequest
+		reader                 spi.PlcReader
+		readRequestInterceptor interceptors.ReadRequestInterceptor
+	}
+	tests := []struct {
+		name      string
+		fields    fields
+		mockSetup func(t *testing.T, fields *fields)
+		want      <-chan apiModel.PlcReadRequestResult
+	}{
+		{
+			name: "execute it",
+			mockSetup: func(t *testing.T, fields *fields) {
+				reader := NewMockPlcReader(t)
+				reader.EXPECT().Read(mock.Anything, mock.Anything).Return(nil)
+				fields.reader = reader
+			},
+			want: nil,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if tt.mockSetup != nil {
+				tt.mockSetup(t, &tt.fields)
+			}
+			d := &DefaultPlcReadRequest{
+				DefaultPlcTagRequest:   tt.fields.DefaultPlcTagRequest,
+				reader:                 tt.fields.reader,
+				readRequestInterceptor: tt.fields.readRequestInterceptor,
+			}
+			assert.Equalf(t, tt.want, d.Execute(), "Execute()")
+		})
+	}
+}
+
+func TestDefaultPlcReadRequest_ExecuteWithContext(t *testing.T) {
+	type fields struct {
+		DefaultPlcTagRequest   *DefaultPlcTagRequest
+		reader                 spi.PlcReader
+		readRequestInterceptor interceptors.ReadRequestInterceptor
+	}
+	type args struct {
+		ctx context.Context
+	}
+	tests := []struct {
+		name         string
+		fields       fields
+		args         args
+		mockSetup    func(t *testing.T, fields *fields)
+		wantAsserter func(t *testing.T, results <-chan apiModel.PlcReadRequestResult) bool
+	}{
+		{
+			name: "execute it",
+			mockSetup: func(t *testing.T, fields *fields) {
+				reader := NewMockPlcReader(t)
+				reader.EXPECT().Read(mock.Anything, mock.Anything).Return(nil)
+				fields.reader = reader
+			},
+		},
+		{
+			name: "execute it with interceptor with one request",
+			mockSetup: func(t *testing.T, fields *fields) {
+				{
+					reader := NewMockPlcReader(t)
+					results := make(chan apiModel.PlcReadRequestResult, 1)
+					results <- NewDefaultPlcReadRequestResult(
+						NewDefaultPlcReadRequest(nil, nil, nil, nil),
+						NewDefaultPlcReadResponse(nil, nil, nil),
+						nil,
+					)
+					reader.EXPECT().Read(mock.Anything, mock.Anything).Return(results)
+					fields.reader = reader
+				}
+				{
+					interceptor := NewMockReadRequestInterceptor(t)
+					interceptor.EXPECT().InterceptReadRequest(mock.Anything, mock.Anything).Return([]apiModel.PlcReadRequest{
+						NewDefaultPlcReadRequest(nil, nil, nil, nil),
+					})
+					fields.readRequestInterceptor = interceptor
+				}
+			},
+			wantAsserter: func(t *testing.T, results <-chan apiModel.PlcReadRequestResult) bool {
+				timeout := time.NewTimer(100 * time.Millisecond)
+				t.Cleanup(func() {
+					utils.CleanupTimer(timeout)
+				})
+				select {
+				case result := <-results:
+					assert.NoError(t, result.GetErr())
+					assert.NotNil(t, result.GetRequest())
+					assert.NotNil(t, result.GetResponse())
+				case <-timeout.C:
+					t.Error("timeout getting a response")
+				}
+				return true
+			},
+		},
+		{
+			name: "execute it with interceptor with three request (panics)",
+			mockSetup: func(t *testing.T, fields *fields) {
+				{
+					reader := NewMockPlcReader(t)
+					results := make(chan apiModel.PlcReadRequestResult, 1)
+					results <- NewDefaultPlcReadRequestResult(nil, nil, nil)
+					reader.EXPECT().Read(mock.Anything, mock.Anything).Return(results)
+					fields.reader = reader
+				}
+				{
+					interceptor := NewMockReadRequestInterceptor(t)
+					interceptor.EXPECT().InterceptReadRequest(mock.Anything, mock.Anything).Return([]apiModel.PlcReadRequest{
+						NewDefaultPlcReadRequest(nil, nil, nil, nil),
+						NewDefaultPlcReadRequest(nil, nil, nil, nil),
+						NewDefaultPlcReadRequest(nil, nil, nil, nil),
+					})
+					fields.readRequestInterceptor = interceptor
+				}
+			},
+			wantAsserter: func(t *testing.T, results <-chan apiModel.PlcReadRequestResult) bool {
+				timeout := time.NewTimer(100 * time.Millisecond)
+				t.Cleanup(func() {
+					utils.CleanupTimer(timeout)
+				})
+				select {
+				case result := <-results:
+					assert.Error(t, result.GetErr())
+					assert.NotNil(t, result.GetRequest())
+					assert.Nil(t, result.GetResponse())
+				case <-timeout.C:
+					t.Error("timeout getting a response")
+				}
+				return true
+			},
+		},
+		{
+			name: "execute it with interceptor with three request (context done)",
+			args: args{
+				ctx: func() context.Context {
+					timeout, cancelFunc := context.WithCancel(context.Background())
+					cancelFunc()
+					return timeout
+				}(),
+			},
+			mockSetup: func(t *testing.T, fields *fields) {
+				{
+					reader := NewMockPlcReader(t)
+					results := make(chan apiModel.PlcReadRequestResult, 1)
+					results <- NewDefaultPlcReadRequestResult(nil, nil, nil)
+					reader.EXPECT().Read(mock.Anything, mock.Anything).Return(results)
+					fields.reader = reader
+				}
+				{
+					interceptor := NewMockReadRequestInterceptor(t)
+					interceptor.EXPECT().InterceptReadRequest(mock.Anything, mock.Anything).Return([]apiModel.PlcReadRequest{
+						NewDefaultPlcReadRequest(nil, nil, nil, nil),
+						NewDefaultPlcReadRequest(nil, nil, nil, nil),
+						NewDefaultPlcReadRequest(nil, nil, nil, nil),
+					})
+					fields.readRequestInterceptor = interceptor
+				}
+			},
+			wantAsserter: func(t *testing.T, results <-chan apiModel.PlcReadRequestResult) bool {
+				timeout := time.NewTimer(100 * time.Millisecond)
+				t.Cleanup(func() {
+					utils.CleanupTimer(timeout)
+				})
+				select {
+				case result := <-results:
+					assert.Error(t, result.GetErr())
+					assert.NotNil(t, result.GetRequest())
+					assert.Nil(t, result.GetResponse())
+				case <-timeout.C:
+					t.Error("timeout getting a response")
+				}
+				return true
+			},
+		},
+		{
+			name: "execute it with interceptor with three request",
+			args: args{
+				ctx: func() context.Context {
+					timeout, cancelFunc := context.WithTimeout(context.Background(), 1*time.Second)
+					t.Cleanup(cancelFunc)
+					return timeout
+				}(),
+			},
+			mockSetup: func(t *testing.T, fields *fields) {
+				{
+					reader := NewMockPlcReader(t)
+					results := make(chan apiModel.PlcReadRequestResult, 1)
+					results <- NewDefaultPlcReadRequestResult(nil, nil, nil)
+					reader.EXPECT().
+						Read(mock.Anything, mock.Anything).
+						Return(results)
+					close(results)
+					fields.reader = reader
+				}
+				{
+					interceptor := NewMockReadRequestInterceptor(t)
+					interceptor.EXPECT().InterceptReadRequest(mock.Anything, mock.Anything).Return([]apiModel.PlcReadRequest{
+						NewDefaultPlcReadRequest(nil, nil, nil, nil),
+						NewDefaultPlcReadRequest(nil, nil, nil, nil),
+						NewDefaultPlcReadRequest(nil, nil, nil, nil),
+					})
+					interceptor.EXPECT().
+						ProcessReadResponses(mock.Anything, mock.Anything, mock.Anything).
+						Return(
+							NewDefaultPlcReadRequestResult(
+								NewDefaultPlcReadRequest(nil, nil, nil, nil),
+								NewDefaultPlcReadResponse(nil, nil, nil),
+								nil,
+							),
+						).Maybe()
+					fields.readRequestInterceptor = interceptor
+				}
+			},
+			wantAsserter: func(t *testing.T, results <-chan apiModel.PlcReadRequestResult) bool {
+				timeout := time.NewTimer(100 * time.Millisecond)
+				t.Cleanup(func() {
+					utils.CleanupTimer(timeout)
+				})
+				select {
+				case result := <-results:
+					assert.NoError(t, result.GetErr())
+					assert.NotNil(t, result.GetRequest())
+					assert.NotNil(t, result.GetResponse())
+				case <-timeout.C:
+					t.Error("timeout getting a response")
+				}
+				return true
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if tt.mockSetup != nil {
+				tt.mockSetup(t, &tt.fields)
+			}
+			d := &DefaultPlcReadRequest{
+				DefaultPlcTagRequest:   tt.fields.DefaultPlcTagRequest,
+				reader:                 tt.fields.reader,
+				readRequestInterceptor: tt.fields.readRequestInterceptor,
+			}
+			result := d.ExecuteWithContext(tt.args.ctx)
+			if tt.wantAsserter != nil {
+				assert.True(t, tt.wantAsserter(t, result), "ExecuteWithContext(%v)", tt.args.ctx)
+			}
+		})
+	}
+}
+
+func TestDefaultPlcReadRequest_GetReadRequestInterceptor(t *testing.T) {
+	type fields struct {
+		DefaultPlcTagRequest   *DefaultPlcTagRequest
+		reader                 spi.PlcReader
+		readRequestInterceptor interceptors.ReadRequestInterceptor
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   interceptors.ReadRequestInterceptor
+	}{
+		{
+			name: "get it",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcReadRequest{
+				DefaultPlcTagRequest:   tt.fields.DefaultPlcTagRequest,
+				reader:                 tt.fields.reader,
+				readRequestInterceptor: tt.fields.readRequestInterceptor,
+			}
+			assert.Equalf(t, tt.want, d.GetReadRequestInterceptor(), "GetReadRequestInterceptor()")
+		})
+	}
+}
+
+func TestDefaultPlcReadRequest_GetReader(t *testing.T) {
+	type fields struct {
+		DefaultPlcTagRequest   *DefaultPlcTagRequest
+		reader                 spi.PlcReader
+		readRequestInterceptor interceptors.ReadRequestInterceptor
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   spi.PlcReader
+	}{
+		{
+			name: "get it",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			d := &DefaultPlcReadRequest{
+				DefaultPlcTagRequest:   tt.fields.DefaultPlcTagRequest,
+				reader:                 tt.fields.reader,
+				readRequestInterceptor: tt.fields.readRequestInterceptor,
+			}
+			assert.Equalf(t, tt.want, d.GetReader(), "GetReader()")
+		})
+	}
+}
+
+func TestNewDefaultPlcReadRequest(t *testing.T) {
+	type args struct {
+		tags                   map[string]apiModel.PlcTag
+		tagNames               []string
+		reader                 spi.PlcReader
+		readRequestInterceptor interceptors.ReadRequestInterceptor
+	}
+	tests := []struct {
+		name string
+		args args
+		want apiModel.PlcReadRequest
+	}{
+		{
+			name: "create it",
+			want: func() apiModel.PlcReadRequest {
+				d := &DefaultPlcReadRequest{}
+				d.DefaultPlcTagRequest = NewDefaultPlcTagRequest(nil, nil)
+				return d
+			}(),
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			assert.Equalf(t, tt.want, NewDefaultPlcReadRequest(tt.args.tags, tt.args.tagNames, tt.args.reader, tt.args.readRequestInterceptor), "NewDefaultPlcReadRequest(%v, %v, %v, %v)", tt.args.tags, tt.args.tagNames, tt.args.reader, tt.args.readRequestInterceptor)
+		})
+	}
+}
+
+func TestNewDefaultPlcReadRequestBuilder(t *testing.T) {
+	type args struct {
+		tagHandler spi.PlcTagHandler
+		reader     spi.PlcReader
+	}
+	tests := []struct {
+		name string
+		args args
+		want apiModel.PlcReadRequestBuilder
+	}{
+		{
+			name: "create it",
+			want: &DefaultPlcReadRequestBuilder{
+				tagNames:     []string{},
+				tagAddresses: map[string]string{},
+				tags:         map[string]apiModel.PlcTag{},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			assert.Equalf(t, tt.want, NewDefaultPlcReadRequestBuilder(tt.args.tagHandler, tt.args.reader), "NewDefaultPlcReadRequestBuilder(%v, %v)", tt.args.tagHandler, tt.args.reader)
+		})
+	}
+}
+
+func TestNewDefaultPlcReadRequestBuilderWithInterceptor(t *testing.T) {
+	type args struct {
+		tagHandler             spi.PlcTagHandler
+		reader                 spi.PlcReader
+		readRequestInterceptor interceptors.ReadRequestInterceptor
+	}
+	tests := []struct {
+		name string
+		args args
+		want apiModel.PlcReadRequestBuilder
+	}{
+		{
+			name: "create it",
+			want: &DefaultPlcReadRequestBuilder{
+				tagNames:     []string{},
+				tagAddresses: map[string]string{},
+				tags:         map[string]apiModel.PlcTag{},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			assert.Equalf(t, tt.want, NewDefaultPlcReadRequestBuilderWithInterceptor(tt.args.tagHandler, tt.args.reader, tt.args.readRequestInterceptor), "NewDefaultPlcReadRequestBuilderWithInterceptor(%v, %v, %v)", tt.args.tagHandler, tt.args.reader, tt.args.readRequestInterceptor)
+		})
+	}
+}
diff --git a/plc4go/spi/model/mock_PlcReader_test.go b/plc4go/spi/model/mock_PlcReader_test.go
new file mode 100644
index 0000000000..b477aae8c3
--- /dev/null
+++ b/plc4go/spi/model/mock_PlcReader_test.go
@@ -0,0 +1,103 @@
+/*
+ * 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"
+)
+
+// MockPlcReader is an autogenerated mock type for the PlcReader type
+type MockPlcReader struct {
+	mock.Mock
+}
+
+type MockPlcReader_Expecter struct {
+	mock *mock.Mock
+}
+
+func (_m *MockPlcReader) EXPECT() *MockPlcReader_Expecter {
+	return &MockPlcReader_Expecter{mock: &_m.Mock}
+}
+
+// Read provides a mock function with given fields: ctx, readRequest
+func (_m *MockPlcReader) Read(ctx context.Context, readRequest apimodel.PlcReadRequest) <-chan apimodel.PlcReadRequestResult {
+	ret := _m.Called(ctx, readRequest)
+
+	var r0 <-chan apimodel.PlcReadRequestResult
+	if rf, ok := ret.Get(0).(func(context.Context, apimodel.PlcReadRequest) <-chan apimodel.PlcReadRequestResult); ok {
+		r0 = rf(ctx, readRequest)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(<-chan apimodel.PlcReadRequestResult)
+		}
+	}
+
+	return r0
+}
+
+// MockPlcReader_Read_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Read'
+type MockPlcReader_Read_Call struct {
+	*mock.Call
+}
+
+// Read is a helper method to define mock.On call
+//   - ctx context.Context
+//   - readRequest apimodel.PlcReadRequest
+func (_e *MockPlcReader_Expecter) Read(ctx interface{}, readRequest interface{}) *MockPlcReader_Read_Call {
+	return &MockPlcReader_Read_Call{Call: _e.mock.On("Read", ctx, readRequest)}
+}
+
+func (_c *MockPlcReader_Read_Call) Run(run func(ctx context.Context, readRequest apimodel.PlcReadRequest)) *MockPlcReader_Read_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(apimodel.PlcReadRequest))
+	})
+	return _c
+}
+
+func (_c *MockPlcReader_Read_Call) Return(_a0 <-chan apimodel.PlcReadRequestResult) *MockPlcReader_Read_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *MockPlcReader_Read_Call) RunAndReturn(run func(context.Context, apimodel.PlcReadRequest) <-chan apimodel.PlcReadRequestResult) *MockPlcReader_Read_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+type mockConstructorTestingTNewMockPlcReader interface {
+	mock.TestingT
+	Cleanup(func())
+}
+
+// NewMockPlcReader creates a new instance of MockPlcReader. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+func NewMockPlcReader(t mockConstructorTestingTNewMockPlcReader) *MockPlcReader {
+	mock := &MockPlcReader{}
+	mock.Mock.Test(t)
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}
diff --git a/plc4go/spi/model/mock_ReadRequestInterceptor_test.go b/plc4go/spi/model/mock_ReadRequestInterceptor_test.go
new file mode 100644
index 0000000000..31a11cae89
--- /dev/null
+++ b/plc4go/spi/model/mock_ReadRequestInterceptor_test.go
@@ -0,0 +1,149 @@
+/*
+ * 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"
+)
+
+// MockReadRequestInterceptor is an autogenerated mock type for the ReadRequestInterceptor type
+type MockReadRequestInterceptor struct {
+	mock.Mock
+}
+
+type MockReadRequestInterceptor_Expecter struct {
+	mock *mock.Mock
+}
+
+func (_m *MockReadRequestInterceptor) EXPECT() *MockReadRequestInterceptor_Expecter {
+	return &MockReadRequestInterceptor_Expecter{mock: &_m.Mock}
+}
+
+// InterceptReadRequest provides a mock function with given fields: ctx, readRequest
+func (_m *MockReadRequestInterceptor) InterceptReadRequest(ctx context.Context, readRequest apimodel.PlcReadRequest) []apimodel.PlcReadRequest {
+	ret := _m.Called(ctx, readRequest)
+
+	var r0 []apimodel.PlcReadRequest
+	if rf, ok := ret.Get(0).(func(context.Context, apimodel.PlcReadRequest) []apimodel.PlcReadRequest); ok {
+		r0 = rf(ctx, readRequest)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).([]apimodel.PlcReadRequest)
+		}
+	}
+
+	return r0
+}
+
+// MockReadRequestInterceptor_InterceptReadRequest_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'InterceptReadRequest'
+type MockReadRequestInterceptor_InterceptReadRequest_Call struct {
+	*mock.Call
+}
+
+// InterceptReadRequest is a helper method to define mock.On call
+//   - ctx context.Context
+//   - readRequest apimodel.PlcReadRequest
+func (_e *MockReadRequestInterceptor_Expecter) InterceptReadRequest(ctx interface{}, readRequest interface{}) *MockReadRequestInterceptor_InterceptReadRequest_Call {
+	return &MockReadRequestInterceptor_InterceptReadRequest_Call{Call: _e.mock.On("InterceptReadRequest", ctx, readRequest)}
+}
+
+func (_c *MockReadRequestInterceptor_InterceptReadRequest_Call) Run(run func(ctx context.Context, readRequest apimodel.PlcReadRequest)) *MockReadRequestInterceptor_InterceptReadRequest_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(apimodel.PlcReadRequest))
+	})
+	return _c
+}
+
+func (_c *MockReadRequestInterceptor_InterceptReadRequest_Call) Return(_a0 []apimodel.PlcReadRequest) *MockReadRequestInterceptor_InterceptReadRequest_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *MockReadRequestInterceptor_InterceptReadRequest_Call) RunAndReturn(run func(context.Context, apimodel.PlcReadRequest) []apimodel.PlcReadRequest) *MockReadRequestInterceptor_InterceptReadRequest_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// ProcessReadResponses provides a mock function with given fields: ctx, readRequest, readResults
+func (_m *MockReadRequestInterceptor) ProcessReadResponses(ctx context.Context, readRequest apimodel.PlcReadRequest, readResults []apimodel.PlcReadRequestResult) apimodel.PlcReadRequestResult {
+	ret := _m.Called(ctx, readRequest, readResults)
+
+	var r0 apimodel.PlcReadRequestResult
+	if rf, ok := ret.Get(0).(func(context.Context, apimodel.PlcReadRequest, []apimodel.PlcReadRequestResult) apimodel.PlcReadRequestResult); ok {
+		r0 = rf(ctx, readRequest, readResults)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(apimodel.PlcReadRequestResult)
+		}
+	}
+
+	return r0
+}
+
+// MockReadRequestInterceptor_ProcessReadResponses_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ProcessReadResponses'
+type MockReadRequestInterceptor_ProcessReadResponses_Call struct {
+	*mock.Call
+}
+
+// ProcessReadResponses is a helper method to define mock.On call
+//   - ctx context.Context
+//   - readRequest apimodel.PlcReadRequest
+//   - readResults []apimodel.PlcReadRequestResult
+func (_e *MockReadRequestInterceptor_Expecter) ProcessReadResponses(ctx interface{}, readRequest interface{}, readResults interface{}) *MockReadRequestInterceptor_ProcessReadResponses_Call {
+	return &MockReadRequestInterceptor_ProcessReadResponses_Call{Call: _e.mock.On("ProcessReadResponses", ctx, readRequest, readResults)}
+}
+
+func (_c *MockReadRequestInterceptor_ProcessReadResponses_Call) Run(run func(ctx context.Context, readRequest apimodel.PlcReadRequest, readResults []apimodel.PlcReadRequestResult)) *MockReadRequestInterceptor_ProcessReadResponses_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(apimodel.PlcReadRequest), args[2].([]apimodel.PlcReadRequestResult))
+	})
+	return _c
+}
+
+func (_c *MockReadRequestInterceptor_ProcessReadResponses_Call) Return(_a0 apimodel.PlcReadRequestResult) *MockReadRequestInterceptor_ProcessReadResponses_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *MockReadRequestInterceptor_ProcessReadResponses_Call) RunAndReturn(run func(context.Context, apimodel.PlcReadRequest, []apimodel.PlcReadRequestResult) apimodel.PlcReadRequestResult) *MockReadRequestInterceptor_ProcessReadResponses_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+type mockConstructorTestingTNewMockReadRequestInterceptor interface {
+	mock.TestingT
+	Cleanup(func())
+}
+
+// NewMockReadRequestInterceptor creates a new instance of MockReadRequestInterceptor. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+func NewMockReadRequestInterceptor(t mockConstructorTestingTNewMockReadRequestInterceptor) *MockReadRequestInterceptor {
+	mock := &MockReadRequestInterceptor{}
+	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 64f4f31497..48edb5c6a1 100644
--- a/plc4go/spi/model/mock_requirements.go
+++ b/plc4go/spi/model/mock_requirements.go
@@ -22,6 +22,7 @@ package model
 import (
 	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
 	"github.com/apache/plc4x/plc4go/spi"
+	"github.com/apache/plc4x/plc4go/spi/interceptors"
 )
 
 // Note this file is a Helper for mockery to generate use mocks from other package
@@ -31,6 +32,11 @@ type PlcBrowser interface {
 	spi.PlcBrowser
 }
 
+// Deprecated: don't use it in productive code
+type PlcReader interface {
+	spi.PlcReader
+}
+
 // Deprecated: don't use it in productive code
 type PlcTagHandler interface {
 	spi.PlcTagHandler
@@ -50,3 +56,8 @@ type PlcBrowseItem interface {
 type PlcQuery interface {
 	apiModel.PlcQuery
 }
+
+// Deprecated: don't use it in productive code
+type ReadRequestInterceptor interface {
+	interceptors.ReadRequestInterceptor
+}