diff --git a/gql_resolvers.go b/gql_resolvers.go index 827a926..2c8322a 100644 --- a/gql_resolvers.go +++ b/gql_resolvers.go @@ -88,7 +88,7 @@ func GQLNodeTypeHash(p graphql.ResolveParams) (interface{}, error) { return string(node.Type), nil } -func GQLThreadListen(p graphql.ResolveParams) (interface{}, error) { +func GQLNodeListen(p graphql.ResolveParams) (interface{}, error) { node, ctx, err := PrepResolve(p) if err != nil { return nil, err diff --git a/gql_test.go b/gql_test.go index 667cfe3..dea64e3 100644 --- a/gql_test.go +++ b/gql_test.go @@ -10,8 +10,13 @@ import ( "crypto/elliptic" ) -func TestGQL(t * testing.T) { - ctx := logTestContext(t, []string{"test", "db"}) +func TestGQL(t *testing.T) { + + +} + +func TestGQLDB(t * testing.T) { + ctx := logTestContext(t, []string{"test", "signal"}) TestUserNodeType := NodeType("TEST_USER") err := ctx.RegisterNodeType(TestUserNodeType, []ExtType{ACLExtType, ACLPolicyExtType}) @@ -28,23 +33,7 @@ func TestGQL(t * testing.T) { ctx.Log.Logf("test", "U1_ID: %s", u1.ID) - ListenerNodeType := NodeType("LISTENER") - err = ctx.RegisterNodeType(ListenerNodeType, []ExtType{ACLExtType, ACLPolicyExtType, ListenerExtType, LockableExtType}) - fatalErr(t, err) - - l1 := NewNode(ctx, RandID(), ListenerNodeType) - l1_policy := NewRequirementOfPolicy(NodeActions{ - l1.ID: Actions{"signal.status"}, - }) - - l1.Extensions[ACLExtType] = NewACLExt(NodeList(u1)) - listener_ext := NewListenerExt(10) - l1.Extensions[ListenerExtType] = listener_ext - l1.Extensions[ACLPolicyExtType] = NewACLPolicyExt(map[PolicyType]Policy{ - RequirementOfPolicyType: &l1_policy, - }) - l1.Extensions[LockableExtType] = NewLockableExt(nil, nil, nil, nil) - + l1, listener_ext := NewSimpleListener(ctx, 10) ctx.Log.Logf("test", "L1_ID: %s", l1.ID) TestThreadNodeType := NodeType("TEST_THREAD") diff --git a/gql_types.go b/gql_types.go index 818d683..1eaf9b4 100644 --- a/gql_types.go +++ b/gql_types.go @@ -67,6 +67,11 @@ var GQLThreadInterfaces = append(GQLLockableInterfaces, GQLInterfaceThread.Inter var GQLTypeGQLNode = NewGQLNodeType(GQLNodeType, GQLThreadInterfaces, func(gql *GQLType) { AddThreadFields(gql.Type) + + gql.Type.AddFieldConfig("Listen", &graphql.Field{ + Type: graphql.String, + Resolve: GQLNodeListen, + }) }) var GQLTypeSignal = NewSingleton(func() *graphql.Object { diff --git a/graph_test.go b/graph_test.go index c0c5e46..83c01f6 100644 --- a/graph_test.go +++ b/graph_test.go @@ -25,10 +25,10 @@ func (t * GraphTester) WaitForStatus(ctx * Context, listener chan Signal, status if signal.Type() == "status" { sig, ok := signal.(StatusSignal) if ok == true { + ctx.Log.Logf("test", "Status received: %s", sig.Status) if sig.Status == status { return signal } - ctx.Log.Logf("test", "Different status received: %s", sig.Status) } else { ctx.Log.Logf("test", "Failed to cast status to StatusSignal: %+v", signal) } @@ -52,6 +52,21 @@ func (t * GraphTester) CheckForNone(listener chan Signal, str string) { } } +const SimpleListenerNodeType = NodeType("SIMPLE_LISTENER") + +func NewSimpleListener(ctx *Context, buffer int) (*Node, *ListenerExt) { + listener := NewNode(ctx, RandID(), SimpleListenerNodeType) + policy := NewAllNodesPolicy([]string{"signal.status", "requirements.write", "requirements.read", "dependencies.write", "dependencies.read", "owner.read", "owner.write"}) + listener_extension := NewListenerExt(buffer) + listener.Extensions[ListenerExtType] = listener_extension + listener.Extensions[ACLPolicyExtType] = NewACLPolicyExt(map[PolicyType]Policy{ + AllNodesPolicyType: &policy, + }) + listener.Extensions[LockableExtType] = NewLockableExt(nil, nil, nil, nil) + + return listener, listener_extension +} + func logTestContext(t * testing.T, components []string) *Context { db, err := badger.Open(badger.DefaultOptions("").WithInMemory(true)) if err != nil { @@ -60,18 +75,15 @@ func logTestContext(t * testing.T, components []string) *Context { ctx, err := NewContext(db, NewConsoleLogger(components)) fatalErr(t, err) + + err = ctx.RegisterNodeType(SimpleListenerNodeType, []ExtType{ACLPolicyExtType, ListenerExtType, LockableExtType}) + fatalErr(t, err) + return ctx } func testContext(t * testing.T) * Context { - db, err := badger.Open(badger.DefaultOptions("").WithInMemory(true)) - if err != nil { - t.Fatal(err) - } - - ctx, err := NewContext(db, NewConsoleLogger([]string{})) - fatalErr(t, err) - return ctx + return logTestContext(t, []string{}) } func fatalErr(t * testing.T, err error) { diff --git a/lockable.go b/lockable.go index 7c1be78..ce777f6 100644 --- a/lockable.go +++ b/lockable.go @@ -33,6 +33,7 @@ func (listener *ListenerExt) Type() ExtType { } func (ext *ListenerExt) Process(context *StateContext, node *Node, signal Signal) error { + context.Graph.Log.Logf("signal", "LISTENER_PROCESS: %s - %+v", node.ID, signal) select { case ext.Chan <- signal: default: diff --git a/policy.go b/policy.go index afe50e7..e021f2b 100644 --- a/policy.go +++ b/policy.go @@ -207,6 +207,33 @@ func (policy *PerNodePolicy) Allows(context *StateContext, principal *Node, acti return false } +func NewAllNodesPolicy(actions Actions) AllNodesPolicy { + if actions == nil { + actions = Actions{} + } + + return AllNodesPolicy{ + Actions: actions, + } +} + +type AllNodesPolicy struct { + Actions Actions `json:"actions"` +} + +const AllNodesPolicyType = PolicyType("ALL_NODES") +func (policy *AllNodesPolicy) Type() PolicyType { + return AllNodesPolicyType +} + +func (policy *AllNodesPolicy) Serialize() ([]byte, error) { + return json.MarshalIndent(policy, "", " ") +} + +func (policy *AllNodesPolicy) Allows(context *StateContext, principal *Node, action string, node *Node) bool { + return policy.Actions.Allows(action) +} + // Extension to allow a node to hold ACL policies type ACLPolicyExt struct { @@ -316,6 +343,16 @@ func NewACLPolicyExtContext() *ACLPolicyExtContext { return &policy, nil }), }, + AllNodesPolicyType: PolicyInfo{ + Load: func(ctx *Context, data []byte) (Policy, error) { + var policy AllNodesPolicy + err := json.Unmarshal(data, &policy) + if err != nil { + return nil, err + } + return &policy, nil + }, + }, }, } } @@ -346,6 +383,12 @@ func NewACLPolicyExt(policies map[PolicyType]Policy) *ACLPolicyExt { policies = map[PolicyType]Policy{} } + for policy_type, policy := range(policies) { + if policy_type != policy.Type() { + panic("POLICY_TYPE_MISMATCH") + } + } + return &ACLPolicyExt{ Policies: policies, }