Skip to content

Commit 79aa4f8

Browse files
committed
fix reading LDIF files on Windows
fix generate JSON object if used: additionalProperties: false update documentation for Kafka and LDAP
1 parent 82f3ef7 commit 79aa4f8

File tree

9 files changed

+171
-41
lines changed

9 files changed

+171
-41
lines changed

config/dynamic/directory/config.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,11 @@ func (c *Config) Parse(config *dynamic.Config, reader dynamic.Reader) error {
6363
if !u.IsAbs() {
6464
if config.Info.Url != nil && config.Info.Url.Scheme == "file" {
6565
if !filepath.IsAbs(file) {
66-
dir := filepath.Dir(config.Info.Url.Path)
66+
path := config.Info.Url.Path
67+
if config.Info.Url.Opaque != "" {
68+
path = config.Info.Url.Opaque
69+
}
70+
dir := filepath.Dir(path)
6771
file = filepath.Join(dir, file)
6872
}
6973
file = filepath.Clean(file)

config/dynamic/directory/ldif.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ type LdifRecord interface {
1919

2020
func (l *Ldif) Parse(config *dynamic.Config, reader dynamic.Reader) error {
2121
l.Records = nil
22-
lines := strings.Split(string(config.Raw), "\n")
22+
s := strings.ReplaceAll(string(config.Raw), "\r\n", "\n")
23+
lines := strings.Split(s, "\n")
2324

2425
if len(lines) > 0 {
2526
kv := strings.SplitN(lines[0], ":", 2)

config/dynamic/dynamictest/reader.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package dynamictest
22

33
import (
44
"errors"
5+
"fmt"
56
"mokapi/config/dynamic"
67
"net/url"
8+
"strings"
79
)
810

911
var NotFound = errors.New("TestReader: config not found")
@@ -18,15 +20,18 @@ func (r *Reader) Read(u *url.URL, v any) (*dynamic.Config, error) {
1820
if r.Data == nil {
1921
return nil, NotFound
2022
}
21-
if c, ok := r.Data[u.String()]; ok {
23+
24+
path := cleanPath(u)
25+
26+
if c, ok := r.Data[path]; ok {
2227
if c.Data == nil {
2328
c.Data = v
2429
err := dynamic.Parse(c, r)
2530
return c, err
2631
}
2732

2833
if p, isParser := c.Data.(dynamic.Parser); isParser {
29-
if _, alreadyParsed := r.parsed[u.String()]; alreadyParsed {
34+
if _, alreadyParsed := r.parsed[path]; alreadyParsed {
3035
return c, nil
3136
}
3237
if err := p.Parse(c, r); err != nil {
@@ -37,7 +42,7 @@ func (r *Reader) Read(u *url.URL, v any) (*dynamic.Config, error) {
3742
r.parsed = make(map[string]bool)
3843
}
3944

40-
r.parsed[u.String()] = true
45+
r.parsed[path] = true
4146
}
4247

4348
return c, nil
@@ -50,3 +55,11 @@ type ReaderFunc func(u *url.URL, v any) (*dynamic.Config, error)
5055
func (f ReaderFunc) Read(u *url.URL, v any) (*dynamic.Config, error) {
5156
return f(u, v)
5257
}
58+
59+
func cleanPath(u *url.URL) string {
60+
if u.Opaque != "" {
61+
// Windows file path
62+
return fmt.Sprintf("%s:%s", u.Scheme, strings.ReplaceAll(u.Opaque, "\\", "/"))
63+
}
64+
return u.String()
65+
}

docs/guides/kafka/overview.md

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,23 @@
22
title: How to mock Apache Kafka with Mokapi
33
description: Mock your Kafka topics with AsyncAPI specification
44
---
5-
# Kafka
5+
# Mocking a Kafka Topic with Mokapi
6+
Mokapi simplifies the process of mocking Kafka topics, enabling you to efficiently test and debug your event-driven applications without the need for a live Kafka environment. Whether you’re validating message schemas, simulating producer-consumer workflows, or testing error-handling scenarios, Mokapi offers a flexible and developer-friendly solution.
67

7-
Kafka is a distributed streaming platform that is commonly used to build real-time data pipelines and streaming applications.
8+
Designed to integrate seamlessly into your projects, Mokapi allows you to mock Kafka brokers and topics using your AsyncAPI specifications. This ensures that your Kafka topics are simulated according to their contract, making it easier to prototype, test, and validate your systems with accuracy. Developers can also simulate Kafka producers and consumers with custom Mokapi Scripts, providing full control over message flows and test scenarios.
89

9-
## AsyncAPI
10+
## Key Features
1011

11-
Mokapi with AsyncAPI can be used to simulate the behavior of a real Kafka system and test event-based applications.
12-
By using Mokapi you can create a test environment that is closely to the production environment.
13-
This allows you to identify and address issues before they impact the end-users.
14-
This reduces the risk of downtime and other issues in the production environment and improves the reliability and robustness of you application.
15-
Overall, Mokapi provides a powerful toolset for testing and validating event-based applications that rely on Kafka.
12+
**Mock Kafka Topics:** Use an AsyncAPI specification to mock Kafka topics by contract, ensuring consistency and adherence to expected behavior.
13+
14+
**Schema Validation:** Mokapi validates message against the schemas to ensure compatibility and compliance between services, reducing runtime issues.
15+
16+
**Realistic Test Data:** Import message payloads or generate representative data to test edge cases, workflows, and error conditions.
17+
18+
**Streamlined Setup:** Avoid the complexity of setting up and maintaining a full Kafka environment, simplifying your development and testing process.
19+
20+
## Why Use Mokapi for Kafka?
21+
By leveraging Mokapi, you can enhance your development workflow and reduce dependencies on external systems, while ensuring the reliability and robustness of your Kafka-based applications. The ability to simulate real-world scenarios and validate messages against contracts reduces the risk of issues in production, accelerates development, and supports a smooth CI/CD pipeline.
22+
23+
## Start Mocking Today!
24+
Refer to [Quick Start](/docs/guides/kafka/quick-start.md) to learn how to create your first Kafka topic mock with Mokapi and streamline the process of testing and debugging event-driven architectures. Mokapi empowers you to build more reliable, scalable, and efficient systems, all while reducing the operational overhead of managing Kafka in your development environment.

docs/guides/ldap/overview.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,7 @@ text: Success
117117
# numEntries: 3
118118
```
119119

120-
To query for the `cn=alice,dc=example,dc=com` user entry, use a command like.
121-
This command will return the details of the alice entry under dc=example,dc=com.
120+
To query the cn=alice,dc=example,dc=com user entry, you can use a command like the following:
122121

123122
```bash
124123
ldapsearch -x -h localhost -p 389 -b "dc=example,dc=com" "(cn=alice)"

ldap/client_test.go

Lines changed: 0 additions & 25 deletions
This file was deleted.

schema/json/generator/object.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func Dictionary() *Tree {
7373
if s == nil {
7474
return false
7575
}
76-
return s.AdditionalProperties != nil
76+
return s.AdditionalProperties != nil && !s.AdditionalProperties.IsAny()
7777
},
7878
Fake: func(r *Request) (interface{}, error) {
7979
s := r.LastSchema()

schema/json/generator/object_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,93 @@ func TestObject(t *testing.T) {
137137
v)
138138
},
139139
},
140+
{
141+
name: "no additional properties",
142+
req: func() *Request {
143+
return &Request{
144+
Path: Path{
145+
&PathElement{Schema: schematest.New("object",
146+
schematest.WithProperty("name", schematest.New("string")),
147+
schematest.WithFreeForm(false),
148+
)},
149+
},
150+
}
151+
},
152+
test: func(t *testing.T, v interface{}, err error) {
153+
require.NoError(t, err)
154+
require.Equal(t, map[string]interface{}{"name": "Ink"}, v)
155+
},
156+
},
157+
{
158+
name: "with additional properties",
159+
req: func() *Request {
160+
return &Request{
161+
Path: Path{
162+
&PathElement{Schema: schematest.New("object",
163+
schematest.WithProperty("name", schematest.New("string")),
164+
schematest.WithFreeForm(true),
165+
)},
166+
},
167+
}
168+
},
169+
test: func(t *testing.T, v interface{}, err error) {
170+
require.NoError(t, err)
171+
require.Equal(t, map[string]interface{}{"name": "Ink"}, v)
172+
},
173+
},
174+
{
175+
name: "with additional properties specific",
176+
req: func() *Request {
177+
return &Request{
178+
Path: Path{
179+
&PathElement{Schema: schematest.New("object",
180+
schematest.WithAdditionalProperties(
181+
schematest.New("object",
182+
schematest.WithProperty("age", schematest.New("integer")),
183+
schematest.WithProperty("gender", schematest.New("string")),
184+
schematest.WithRequired("age", "gender"),
185+
),
186+
),
187+
)},
188+
},
189+
}
190+
},
191+
test: func(t *testing.T, v interface{}, err error) {
192+
require.NoError(t, err)
193+
require.Equal(t,
194+
map[string]interface{}{
195+
"brace": map[string]interface{}{
196+
"age": int64(-2231804065324102411),
197+
"gender": "female",
198+
},
199+
"child": map[string]interface{}{
200+
"age": int64(-5996906719781834924),
201+
"gender": "male",
202+
},
203+
"comb": map[string]interface{}{
204+
"age": int64(298783498632242168),
205+
"gender": "male",
206+
},
207+
"life": map[string]interface{}{
208+
"age": int64(-7574890634918414754),
209+
"gender": "male",
210+
},
211+
"person": map[string]interface{}{
212+
"age": int64(-5048116001741826297),
213+
"gender": "female",
214+
},
215+
"string": map[string]interface{}{
216+
"age": int64(-7377528278928660358),
217+
"gender": "female",
218+
},
219+
"sunshine": map[string]interface{}{
220+
"age": int64(-3652171958352792229),
221+
"gender": "male",
222+
},
223+
},
224+
v)
225+
},
226+
},
140227
}
141228

142229
for _, tc := range testcases {

schema/json/schema/marshal_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package schema
2+
3+
import (
4+
"encoding/json"
5+
"github.com/stretchr/testify/require"
6+
"testing"
7+
)
8+
9+
func TestRef_MarshalJSON(t *testing.T) {
10+
testcases := []struct {
11+
name string
12+
s *Schema
13+
test func(t *testing.T, s string, err error)
14+
}{
15+
{
16+
name: "empty type",
17+
s: &Schema{},
18+
test: func(t *testing.T, s string, err error) {
19+
require.NoError(t, err)
20+
require.Equal(t, "{}", s)
21+
},
22+
},
23+
{
24+
name: "with type",
25+
s: &Schema{Type: Types{"string"}},
26+
test: func(t *testing.T, s string, err error) {
27+
require.NoError(t, err)
28+
require.Equal(t, `{"type":"string"}`, s)
29+
},
30+
},
31+
}
32+
33+
t.Parallel()
34+
for _, tc := range testcases {
35+
tc := tc
36+
t.Run(tc.name, func(t *testing.T) {
37+
t.Parallel()
38+
b, err := json.Marshal(tc.s)
39+
tc.test(t, string(b), err)
40+
})
41+
}
42+
}

0 commit comments

Comments
 (0)