Skip to content

Commit

Permalink
Merge pull request #986 from Permify/test-coverage
Browse files Browse the repository at this point in the history
test: expand coverage tests
  • Loading branch information
tolgaOzen authored Dec 31, 2023
2 parents c784919 + e65605a commit d0f0fac
Show file tree
Hide file tree
Showing 5 changed files with 333 additions and 5 deletions.
45 changes: 45 additions & 0 deletions internal/storage/memory/watch_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package memory

import (
"context"
"fmt"
"time"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/Permify/permify/internal/storage/memory/migrations"
"github.com/Permify/permify/pkg/database/memory"
)

var _ = Describe("Watch", func() {
var db *memory.Memory

var watcher *Watch

BeforeEach(func() {
database, err := memory.New(migrations.Schema)
Expect(err).ShouldNot(HaveOccurred())
db = database

watcher = NewWatcher(db)
})

AfterEach(func() {
err := db.Close()
Expect(err).ShouldNot(HaveOccurred())
})

Context("Watch", func() {
It("watch", func() {
_, errs := watcher.Watch(context.Background(), "t1", "")
select {
case err := <-errs:
// Handle and assert the error
Expect(err).ShouldNot(HaveOccurred())
case <-time.After(time.Second * 10):
fmt.Println("test timed out")
}
})
})
})
8 changes: 7 additions & 1 deletion internal/storage/postgres/postgres_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,15 @@ func postgresDB(postgresVersion string) database.Database {
Expect(err).ShouldNot(HaveOccurred())
}

// Execute the command in the container
_, _, execErr := postgres.Exec(ctx, []string{"psql", "-U", "postgres", "-c", "ALTER SYSTEM SET track_commit_timestamp = on;"})
if execErr != nil {
Expect(execErr).ShouldNot(HaveOccurred())
}

cmd := []string{"sh", "-c", "export PGPASSWORD=postgres" + "; psql -U postgres -d permify -c 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;'"}

_, _, err = postgres.Exec(context.Background(), cmd)
_, _, err = postgres.Exec(ctx, cmd)
if err != nil {
Expect(err).ShouldNot(HaveOccurred())
}
Expand Down
12 changes: 8 additions & 4 deletions internal/storage/postgres/watch.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import (
"errors"
"fmt"
"log/slog"
"strings"
"time"

"google.golang.org/protobuf/proto"
"github.com/golang/protobuf/jsonpb"

"google.golang.org/protobuf/types/known/anypb"

"github.com/Masterminds/squirrel"
Expand Down Expand Up @@ -310,17 +312,19 @@ func (w *Watch) getChanges(ctx context.Context, value types.XID8, tenantID strin

rt := storage.Attribute{}

var valueBytes []byte
var valueStr string

// Scan the result row into a RelationTuple instance.
err = trows.Scan(&rt.EntityType, &rt.EntityID, &rt.Attribute, &valueBytes, &expiredXID)
err = arows.Scan(&rt.EntityType, &rt.EntityID, &rt.Attribute, &valueStr, &expiredXID)
if err != nil {
slog.Error("Error while scanning row for attributes", slog.Any("error", err))
return nil, err
}

// Unmarshal the JSON data from `valueStr` into `rt.Value`.
rt.Value = &anypb.Any{}
err = proto.Unmarshal(valueBytes, rt.Value)
unmarshaler := &jsonpb.Unmarshaler{}
err = unmarshaler.Unmarshal(strings.NewReader(valueStr), rt.Value)
if err != nil {
slog.Error("Failed to unmarshal attribute value", slog.Any("error", err))
return nil, err
Expand Down
112 changes: 112 additions & 0 deletions internal/storage/postgres/watch_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package postgres

import (
"context"
"fmt"
"os"
"time"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/Permify/permify/pkg/attribute"
"github.com/Permify/permify/pkg/database"
PQDatabase "github.com/Permify/permify/pkg/database/postgres"
base "github.com/Permify/permify/pkg/pb/base/v1"
"github.com/Permify/permify/pkg/tuple"
)

var _ = Describe("Watch", func() {
var db database.Database
var dataWriter *DataWriter
var watcher *Watch

BeforeEach(func() {
version := os.Getenv("POSTGRES_VERSION")

if version == "" {
version = "14"
}

db = postgresDB(version)
dataWriter = NewDataWriter(db.(*PQDatabase.Postgres))
watcher = NewWatcher(db.(*PQDatabase.Postgres))
})

AfterEach(func() {
err := db.Close()
Expect(err).ShouldNot(HaveOccurred())
})

Context("Watch", func() {
It("watch", func() {
ctx := context.Background()

tup1, err := tuple.Tuple("organization:organization-1#admin@user:user-1")
Expect(err).ShouldNot(HaveOccurred())

tuples := database.NewTupleCollection([]*base.Tuple{
tup1,
}...)

token1, err := dataWriter.Write(ctx, "t1", tuples, database.NewAttributeCollection())
Expect(err).ShouldNot(HaveOccurred())
Expect(token1.String()).ShouldNot(Equal(""))

changes, errs := watcher.Watch(ctx, "t1", token1.String())

time.Sleep(100 * time.Millisecond)

go func() {
defer GinkgoRecover()

attr1, err := attribute.Attribute("organization:organization-1$public|boolean:true")
Expect(err).ShouldNot(HaveOccurred())

attr2, err := attribute.Attribute("organization:organization-1$ip_addresses|string[]:127.0.0.1,127.0.0.2")
Expect(err).ShouldNot(HaveOccurred())

attr3, err := attribute.Attribute("organization:organization-3$balance|double:234.344")
Expect(err).ShouldNot(HaveOccurred())

tup1, err := tuple.Tuple("organization:organization-1#admin@user:user-1")
Expect(err).ShouldNot(HaveOccurred())

tup2, err := tuple.Tuple("organization:organization-1#admin@user:user-4")
Expect(err).ShouldNot(HaveOccurred())

tup3, err := tuple.Tuple("organization:organization-1#admin@user:user-2")
Expect(err).ShouldNot(HaveOccurred())

attributes1 := database.NewAttributeCollection([]*base.Attribute{
attr1,
attr2,
attr3,
}...)

tuples1 := database.NewTupleCollection([]*base.Tuple{
tup1,
tup2,
tup3,
}...)

time.Sleep(time.Second)
token2, err := dataWriter.Write(ctx, "t1", tuples1, attributes1)
Expect(err).ShouldNot(HaveOccurred())
Expect(token2.String()).ShouldNot(Equal(""))
}()

select {
case change := <-changes:
// Test the received change
Expect(change.DataChanges).ShouldNot(BeNil())
// Additional assertions about the structure and content of 'change'
case err := <-errs:
// Handle and assert the error
Expect(err).ShouldNot(HaveOccurred())
case <-time.After(time.Second * 10):
fmt.Println("test timed out")
}
})
})
})
161 changes: 161 additions & 0 deletions pkg/database/iterators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,3 +279,164 @@ func TestAttributeIterator(t *testing.T) {
t.Error("Expected false for HasNext(), but got true")
}
}

func TestUniqueAttributeIterator(t *testing.T) {
isPublic, err := anypb.New(&base.BooleanValue{Data: true})
assert.NoError(t, err)

// Create some attributes
attribute1 := &base.Attribute{
Entity: &base.Entity{
Type: "entity",
Id: "e1",
},
Attribute: "public",
Value: isPublic,
}

attribute2 := &base.Attribute{
Entity: &base.Entity{
Type: "entity",
Id: "e2",
},
Attribute: "public",
Value: isPublic,
}

attribute3 := &base.Attribute{
Entity: &base.Entity{
Type: "entity",
Id: "e3",
},
Attribute: "public",
Value: isPublic,
}

attribute4 := &base.Attribute{
Entity: &base.Entity{
Type: "entity",
Id: "e4",
},
Attribute: "public",
Value: isPublic,
}

attribute5 := &base.Attribute{
Entity: &base.Entity{
Type: "entity",
Id: "e5",
},
Attribute: "public",
Value: isPublic,
}

attribute6 := &base.Attribute{
Entity: &base.Entity{
Type: "entity",
Id: "e6",
},
Attribute: "public",
Value: isPublic,
}

// Create a tuple iterators
attributeIterator1 := NewAttributeIterator(attribute1, attribute2, attribute3, attribute6)
attributeIterator2 := NewAttributeIterator(attribute6, attribute1, attribute2, attribute4, attribute5)

// Create a unique iterator
uniqueIterator := NewUniqueAttributeIterator(attributeIterator1, attributeIterator2)

// Test HasNext() and GetNext() methods
if !uniqueIterator.HasNext() {
t.Error("Expected true for HasNext(), but got false")
}
i, _ := uniqueIterator.GetNext()
if i != attribute1 {
t.Error("Expected tuple1 for GetNext(), but got something else")
}
if !uniqueIterator.HasNext() {
t.Error("Expected true for HasNext(), but got false")
}
i, _ = uniqueIterator.GetNext()
if i != attribute2 {
t.Error("Expected tuple2 for GetNext(), but got something else")
}
if !uniqueIterator.HasNext() {
t.Error("Expected true for HasNext(), but got false")
}
i, _ = uniqueIterator.GetNext()
if i != attribute3 {
t.Error("Expected tuple3 for GetNext(), but got something else")
}
if !uniqueIterator.HasNext() {
t.Error("Expected false for HasNext(), but got true")
}
i, _ = uniqueIterator.GetNext()
if i != attribute6 {
t.Error("Expected tuple6 for GetNext(), but got something else")
}
if !uniqueIterator.HasNext() {
t.Error("Expected false for HasNext(), but got true")
}
i, _ = uniqueIterator.GetNext()
if i != attribute4 {
t.Error("Expected tuple4 for GetNext(), but got something else")
}
if !uniqueIterator.HasNext() {
t.Error("Expected false for HasNext(), but got true")
}
i, _ = uniqueIterator.GetNext()
if i != attribute5 {
t.Error("Expected tuple5 for GetNext(), but got something else")
}
if uniqueIterator.HasNext() {
t.Error("Expected false for HasNext(), but got true")
}
}

func TestEntityIterator(t *testing.T) {
// Create some tuples
en1 := &base.Entity{
Type: "entity",
Id: "e1",
}

en2 := &base.Entity{
Type: "entity",
Id: "e2",
}

en3 := &base.Entity{
Type: "entity",
Id: "e3",
}

// Create a entity collection and add the tuples
entityCollection := NewEntityCollection(en1, en2, en3)

// Create an entity iterator
entityIterator := entityCollection.CreateEntityIterator()

// Test HasNext() and GetNext() methods
if !entityIterator.HasNext() {
t.Error("Expected true for HasNext(), but got false")
}
if entityIterator.GetNext() != en1 {
t.Error("Expected tuple1 for GetNext(), but got something else")
}
if !entityIterator.HasNext() {
t.Error("Expected true for HasNext(), but got false")
}
if entityIterator.GetNext() != en2 {
t.Error("Expected tuple2 for GetNext(), but got something else")
}
if !entityIterator.HasNext() {
t.Error("Expected true for HasNext(), but got false")
}
if entityIterator.GetNext() != en3 {
t.Error("Expected tuple3 for GetNext(), but got something else")
}
if entityIterator.HasNext() {
t.Error("Expected false for HasNext(), but got true")
}
}

0 comments on commit d0f0fac

Please sign in to comment.