func TestMakeDirs(t *testing.T) { // skip exists `parent` and create `child` conn := &mockConn{} conn.On("Exists", "/parent").Return(true, nil, nil).Once() conn.On("Exists", "/parent/child").Return(false, nil, nil).Once() conn.On("Create", "/parent/child", []byte{}, int32(PERSISTENT), OPEN_ACL_UNSAFE).Return("", nil).Once() assert.NoError(t, MakeDirs(conn, "/parent/child/node", false, nil)) conn.AssertExpectations(t) // fail to create `parent` conn = &mockConn{} conn.On("Exists", "/parent").Return(true, nil, zk.ErrAPIError).Once() assert.EqualError(t, MakeDirs(conn, "/parent/child/node", false, nil), zk.ErrAPIError.Error()) conn.AssertExpectations(t) // create `child` which exists conn = &mockConn{} conn.On("Exists", "/parent").Return(true, nil, nil).Once() conn.On("Exists", "/parent/child").Return(false, nil, nil).Once() conn.On("Create", "/parent/child", []byte{}, int32(PERSISTENT), OPEN_ACL_UNSAFE).Return("", zk.ErrNodeExists).Once() assert.NoError(t, MakeDirs(conn, "/parent/child/node", false, nil)) conn.AssertExpectations(t) // create `child` with default ACLs conn = &mockConn{} acls := &mockACLProvider{} conn.On("Exists", "/parent").Return(true, nil, nil).Once() conn.On("Exists", "/parent/child").Return(false, nil, nil).Once() acls.On("GetAclForPath", "/parent/child").Return([]zk.ACL{}).Once() acls.On("GetDefaultAcl").Return(zk.AuthACL(zk.PermAdmin)).Once() conn.On("Create", "/parent/child", []byte{}, int32(PERSISTENT), zk.AuthACL(zk.PermAdmin)).Return("", nil).Once() assert.NoError(t, MakeDirs(conn, "/parent/child/node", false, acls)) conn.AssertExpectations(t) acls.AssertExpectations(t) }
func TestTransaction(t *testing.T) { newMockContainer().WithNamespace("parent").Test(t, func(client CuratorFramework, conn *mockConn, compress *mockCompressionProvider, version int32) { acls := zk.AuthACL(zk.PermRead) compress.On("Compress", "/node1", []byte("default")).Return([]byte("compressed(default)"), nil).Once() compress.On("Compress", "/node3", []byte("data")).Return([]byte("compressed(data)"), nil).Once() conn.On("Exists", "/parent").Return(true, nil, nil).Once() conn.On("Multi", mock.Anything).Return([]zk.MultiResponse{ {Stat: nil, String: "/parent/node1"}, {Stat: nil, String: ""}, {Stat: &zk.Stat{}, String: ""}, {Stat: nil, String: ""}, }, nil).Once() results, err := client.InTransaction(). Create().WithMode(PERSISTENT_SEQUENTIAL).WithACL(acls...).Compressed().ForPath("/node1"). Delete().WithVersion(version).ForPath("/node2"). SetData().WithVersion(version+1).Compressed().ForPathWithData("/node3", []byte("data")). Check().WithVersion(version + 2).ForPath("/node4"). Commit() assert.NoError(t, err) assert.Equal(t, conn.operations, []interface{}{ &zk.CreateRequest{ Path: "/parent/node1", Data: []byte("compressed(default)"), Acl: acls, Flags: int32(PERSISTENT_SEQUENTIAL), }, &zk.DeleteRequest{ Path: "/parent/node2", Version: version, }, &zk.SetDataRequest{ Path: "/parent/node3", Data: []byte("compressed(data)"), Version: version + 1, }, &zk.CheckVersionRequest{ Path: "/parent/node4", Version: version + 2, }, }) assert.Equal(t, results, []TransactionResult{ { Type: OP_CREATE, ForPath: "/parent/node1", ResultPath: "/node1", }, { Type: OP_DELETE, ForPath: "/parent/node2", }, { Type: OP_SET_DATA, ForPath: "/parent/node3", ResultStat: &zk.Stat{}, }, { Type: OP_CHECK, ForPath: "/parent/node4", }, }) }) }
func (c *mockContainer) Test(t *testing.T, callback interface{}) { var client CuratorFramework var events chan zk.Event var wg *sync.WaitGroup zookeeperConnection := &mockConn{log: t.Logf} zookeeperDialer := &mockZookeeperDialer{log: t.Logf} ensembleProvider := &mockEnsembleProvider{} compressionProvider := &mockCompressionProvider{log: t.Logf} retryPolicy := &mockRetryPolicy{log: t.Logf} aclProvider := &mockACLProvider{log: t.Logf} data := []byte("data") version := rand.Int31() stat := &zk.Stat{Version: version, Mtime: time.Now().Unix()} acls := zk.AuthACL(zk.PermRead) if c.builder.ZookeeperDialer == nil { c.builder.ZookeeperDialer = zookeeperDialer } if c.builder.EnsembleProvider == nil { c.builder.EnsembleProvider = ensembleProvider } if c.builder.CompressionProvider == nil { c.builder.CompressionProvider = compressionProvider } if c.builder.RetryPolicy == nil { c.builder.RetryPolicy = retryPolicy } if c.builder.AclProvider == nil { c.builder.AclProvider = aclProvider } fn := reflect.TypeOf(callback) assert.Equal(t, reflect.Func, fn.Kind()) args := make([]reflect.Value, fn.NumIn()) for i := 0; i < fn.NumIn(); i++ { switch argType := fn.In(i); argType { case reflect.TypeOf(c.builder): args[i] = reflect.ValueOf(c.builder) case reflect.TypeOf((*CuratorFramework)(nil)).Elem(): client = c.builder.Build() args[i] = reflect.ValueOf(client) case reflect.TypeOf((*ZookeeperConnection)(nil)).Elem(), reflect.TypeOf(zookeeperConnection): args[i] = reflect.ValueOf(zookeeperConnection) case reflect.TypeOf((*ZookeeperDialer)(nil)).Elem(), reflect.TypeOf(zookeeperDialer): args[i] = reflect.ValueOf(zookeeperDialer) case reflect.TypeOf((*EnsembleProvider)(nil)).Elem(), reflect.TypeOf(ensembleProvider): args[i] = reflect.ValueOf(ensembleProvider) case reflect.TypeOf((*ZookeeperDialer)(nil)).Elem(), reflect.TypeOf(compressionProvider): args[i] = reflect.ValueOf(compressionProvider) case reflect.TypeOf((*RetryPolicy)(nil)).Elem(), reflect.TypeOf(retryPolicy): args[i] = reflect.ValueOf(retryPolicy) case reflect.TypeOf((*ACLProvider)(nil)).Elem(), reflect.TypeOf(aclProvider): args[i] = reflect.ValueOf(aclProvider) case reflect.TypeOf(events): events = make(chan zk.Event) args[i] = reflect.ValueOf(events) case reflect.TypeOf(wg): wg = new(sync.WaitGroup) args[i] = reflect.ValueOf(wg) case reflect.TypeOf(data): args[i] = reflect.ValueOf(data) case reflect.TypeOf(version): args[i] = reflect.ValueOf(version) case reflect.TypeOf(stat): args[i] = reflect.ValueOf(stat) case reflect.TypeOf(acls): args[i] = reflect.ValueOf(acls) default: t.Errorf("unknown arg type: %s", fn.In(i)) } } if client != nil { if c.builder.EnsembleProvider == ensembleProvider { ensembleProvider.On("ConnectionString").Return("connStr").Once() ensembleProvider.On("Start").Return(nil).Once() ensembleProvider.On("Close").Return(nil).Once() } if c.builder.ZookeeperDialer == zookeeperDialer { zookeeperDialer.On("Dial", mock.AnythingOfType("string"), c.builder.SessionTimeout, c.builder.CanBeReadOnly).Return(zookeeperConnection, events, nil).Once() } assert.NoError(t, client.Start()) } if wg != nil { wg.Add(1) } reflect.ValueOf(callback).Call(args) if wg != nil { wg.Wait() } if client != nil { if c.builder.ZookeeperDialer == zookeeperDialer { zookeeperConnection.On("Close").Return().Once() } assert.NoError(t, client.Close()) } if events != nil { close(events) } zookeeperConnection.AssertExpectations(t) zookeeperDialer.AssertExpectations(t) ensembleProvider.AssertExpectations(t) compressionProvider.AssertExpectations(t) retryPolicy.AssertExpectations(t) aclProvider.AssertExpectations(t) }
package curator import ( "github.com/samuel/go-zookeeper/zk" ) var ( OPEN_ACL_UNSAFE = zk.WorldACL(zk.PermAll) CREATOR_ALL_ACL = zk.AuthACL(zk.PermAll) READ_ACL_UNSAFE = zk.WorldACL(zk.PermRead) ) type ACLProvider interface { // Return the ACL list to use by default GetDefaultAcl() []zk.ACL // Return the ACL list to use for the given path GetAclForPath(path string) []zk.ACL } type defaultACLProvider struct { defaultAcls []zk.ACL } func (p *defaultACLProvider) GetDefaultAcl() []zk.ACL { return p.defaultAcls } func (p *defaultACLProvider) GetAclForPath(path string) []zk.ACL { return p.defaultAcls }