diff --git a/artifactregistry.go b/artifactregistry.go index 7c028ec..8c8f8f3 100644 --- a/artifactregistry.go +++ b/artifactregistry.go @@ -11,81 +11,179 @@ import ( var _ ArtifactRegistry = (*InMemoryArtifactRegistry)(nil) type InMemoryArtifactRegistry struct { - ArtifactMap map[string][]ArtifactID + ArtifactMap map[string][]ArtifactRegistryEntry mu sync.RWMutex // Mutex to protect concurrent access } -func (r *InMemoryArtifactRegistry) Load() error { return nil } - -func (r *InMemoryArtifactRegistry) Save() error { return nil } - -func (r *InMemoryArtifactRegistry) AddArtifact(processorName string, artifactID ArtifactID) { +func (r *InMemoryArtifactRegistry) Add(processorName string, e ArtifactRegistryEntry) error { r.mu.Lock() defer r.mu.Unlock() if r.ArtifactMap == nil { - r.ArtifactMap = map[string][]ArtifactID{} + r.ArtifactMap = map[string][]ArtifactRegistryEntry{} } if _, ok := r.ArtifactMap[processorName]; !ok { - r.ArtifactMap[processorName] = make([]ArtifactID, 0) + r.ArtifactMap[processorName] = make([]ArtifactRegistryEntry, 0) } - r.ArtifactMap[processorName] = append(r.ArtifactMap[processorName], artifactID) + r.ArtifactMap[processorName] = append(r.ArtifactMap[processorName], e) + + return nil } -func (r *InMemoryArtifactRegistry) RemoveArtifact(processorName string, artifactID ArtifactID) { +func (r *InMemoryArtifactRegistry) Remove(processorName string, artifactID ArtifactID) error { r.mu.Lock() defer r.mu.Unlock() + if _, ok := r.ArtifactMap[processorName]; !ok { - return + return nil } if r.ArtifactMap == nil { - r.ArtifactMap = map[string][]ArtifactID{} + r.ArtifactMap = map[string][]ArtifactRegistryEntry{} } - var artifacts []ArtifactID - for _, file := range r.ArtifactMap[processorName] { - if file != artifactID { - artifacts = append(artifacts, file) + var artifacts []ArtifactRegistryEntry + for _, entry := range r.ArtifactMap[processorName] { + if entry.ArtifactID != artifactID { + artifacts = append(artifacts, entry) } } r.ArtifactMap[processorName] = artifacts + + return nil +} + +func (r *InMemoryArtifactRegistry) FindByID(processorName string, artifactID ArtifactID) (entry ArtifactRegistryEntry, found bool, err error) { + all, err := r.FindAll(processorName) + if err != nil { + return ArtifactRegistryEntry{}, false, err + } + + for _, e := range all { + if e.ArtifactID == artifactID { + return e, true, nil + } + } + + return ArtifactRegistryEntry{}, false, nil } -func (r *InMemoryArtifactRegistry) Artifacts(processorName string) []ArtifactID { +func (r *InMemoryArtifactRegistry) FindAll(processorName string) ([]ArtifactRegistryEntry, error) { if r.ArtifactMap == nil { - r.ArtifactMap = map[string][]ArtifactID{} + r.ArtifactMap = map[string][]ArtifactRegistryEntry{} } values, ok := r.ArtifactMap[processorName] if !ok { - return nil + return nil, nil } - return values + return values, nil } +func (r *InMemoryArtifactRegistry) Load() error { return nil } + +func (r *InMemoryArtifactRegistry) Save() error { return nil } + +type JsonArtifactRegistryEntry struct { + ArtifactID ArtifactID `json:"artifactId"` + Metadata map[string]any `json:"metadata"` +} + +var _ ArtifactRegistry = (*JSONArtifactRegistry)(nil) + // JSONArtifactRegistry implementation of a ArtifactRegistry that is saved as a JSON file. type JSONArtifactRegistry struct { - UseAbsolutePaths bool `json:"-"` - - GeneratedAt time.Time `json:"generatedAt"` - ArtifactMap map[string]*JSONArtifactRegistryProcessor `json:"files"` - FilePath string `json:"-"` - FileSystem FileSystem `json:"-"` - mu sync.RWMutex // Mutex to protect concurrent access - CurrentTimeProvider func() time.Time `json:"-"` + UseAbsolutePaths bool `json:"-"` + FileSystem FileSystem `json:"-"` + FilePath string `json:"-"` + CurrentTimeProvider func() time.Time `json:"-"` + + GeneratedAt time.Time `json:"generatedAt"` + Entries map[string][]JsonArtifactRegistryEntry `json:"entries"` + mu sync.RWMutex // Mutex to protect concurrent access +} + +func (r *JSONArtifactRegistry) Add(processorName string, e ArtifactRegistryEntry) error { + r.mu.Lock() + defer r.mu.Unlock() + + if _, ok := r.Entries[processorName]; !ok { + r.Entries[processorName] = make([]JsonArtifactRegistryEntry, 0) + } + + r.Entries[processorName] = append(r.Entries[processorName], JsonArtifactRegistryEntry{ + ArtifactID: e.ArtifactID, + Metadata: e.Metadata, + }) + + return nil +} + +func (r *JSONArtifactRegistry) Remove(processorName string, artifactID ArtifactID) error { + r.mu.Lock() + defer r.mu.Unlock() + + if _, ok := r.Entries[processorName]; !ok { + return nil + } + + var entries []JsonArtifactRegistryEntry + for _, entry := range r.Entries[processorName] { + if entry.ArtifactID != artifactID { + entries = append(entries, entry) + } + } + + r.Entries[processorName] = entries + + return nil +} + +func (r *JSONArtifactRegistry) FindByID(processorName string, artifactID ArtifactID) (ArtifactRegistryEntry, bool, error) { + r.mu.RLock() + defer r.mu.RUnlock() + + if _, ok := r.Entries[processorName]; !ok { + return ArtifactRegistryEntry{}, false, nil + } + + for _, entry := range r.Entries[processorName] { + if entry.ArtifactID == artifactID { + return ArtifactRegistryEntry{ + ArtifactID: entry.ArtifactID, + Metadata: entry.Metadata, + }, true, nil + } + } + + return ArtifactRegistryEntry{}, false, nil } -type JSONArtifactRegistryProcessor struct { - Artifacts []ArtifactID `json:"files"` +func (r *JSONArtifactRegistry) FindAll(processorName string) ([]ArtifactRegistryEntry, error) { + r.mu.RLock() + defer r.mu.RUnlock() + + if _, ok := r.Entries[processorName]; !ok { + return nil, nil + } + + var entries []ArtifactRegistryEntry + for _, entry := range r.Entries[processorName] { + entries = append(entries, ArtifactRegistryEntry{ + ArtifactID: entry.ArtifactID, + Metadata: entry.Metadata, + }) + } + + return entries, nil } // NewJSONArtifactRegistry returns a new artifact file registry. func NewJSONArtifactRegistry(fileName string, fs FileSystem) *JSONArtifactRegistry { return &JSONArtifactRegistry{ - ArtifactMap: map[string]*JSONArtifactRegistryProcessor{}, - FilePath: fileName, + Entries: make(map[string][]JsonArtifactRegistryEntry), + FilePath: fileName, CurrentTimeProvider: func() time.Time { return time.Now() }, @@ -135,46 +233,3 @@ func (r *JSONArtifactRegistry) Save() error { return nil } - -func (r *JSONArtifactRegistry) AddArtifact(processorName string, artifactID ArtifactID) { - r.mu.Lock() - defer r.mu.Unlock() - - if r.ArtifactMap == nil { - r.ArtifactMap = map[string]*JSONArtifactRegistryProcessor{} - } - - if _, ok := r.ArtifactMap[processorName]; !ok { - r.ArtifactMap[processorName] = &JSONArtifactRegistryProcessor{} - } - r.ArtifactMap[processorName].Artifacts = append(r.ArtifactMap[processorName].Artifacts, artifactID) -} - -func (r *JSONArtifactRegistry) RemoveArtifact(processorName string, artifactID ArtifactID) { - r.mu.Lock() - defer r.mu.Unlock() - - if _, ok := r.ArtifactMap[processorName]; !ok { - return - } - - var files []ArtifactID - for _, file := range r.ArtifactMap[processorName].Artifacts { - if file != artifactID { - files = append(files, file) - } - } - - r.ArtifactMap[processorName].Artifacts = files -} - -func (r *JSONArtifactRegistry) Artifacts(processorName string) []ArtifactID { - r.mu.RLock() - defer r.mu.RUnlock() - - artifacts, ok := r.ArtifactMap[processorName] - if !ok { - return nil - } - return artifacts.Artifacts -} diff --git a/artifactregistry_test.go b/artifactregistry_test.go index b952073..9dc8f9b 100644 --- a/artifactregistry_test.go +++ b/artifactregistry_test.go @@ -32,7 +32,11 @@ func TestJSONArtifactRegistry_Load(t *testing.T) { expectedError: nil, expectedValue: &JSONArtifactRegistry{ GeneratedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), - ArtifactMap: map[string]*JSONArtifactRegistryProcessor{"processor1": {Artifacts: []ArtifactID{"file1.txt"}}}, + Entries: map[string][]JsonArtifactRegistryEntry{"processor1": { + { + ArtifactID: "file1.txt", + }, + }}, }, }, }, @@ -45,7 +49,7 @@ func TestJSONArtifactRegistry_Load(t *testing.T) { expectedError: nil, expectedValue: &JSONArtifactRegistry{ GeneratedAt: time.Time{}, - ArtifactMap: nil, + Entries: nil, }, }, }, @@ -58,7 +62,7 @@ func TestJSONArtifactRegistry_Load(t *testing.T) { expectedError: fmt.Errorf("failed loading artifact file registry: unexpected end of JSON input"), expectedValue: &JSONArtifactRegistry{ GeneratedAt: time.Time{}, - ArtifactMap: nil, + Entries: nil, }, }, }, @@ -66,7 +70,6 @@ func TestJSONArtifactRegistry_Load(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - // Setup filePath := "test_registry.json" fs := &mockFileSystem{} @@ -78,10 +81,8 @@ func TestJSONArtifactRegistry_Load(t *testing.T) { return time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC) } - // Act err = registry.Load() - // Assert if tt.then.expectedError != nil { assert.Error(t, err) } else { @@ -107,22 +108,21 @@ func TestJSONArtifactRegistry_Save(t *testing.T) { name: "Successful Save", given: &JSONArtifactRegistry{ UseAbsolutePaths: false, - ArtifactMap: map[string]*JSONArtifactRegistryProcessor{ + Entries: map[string][]JsonArtifactRegistryEntry{ "processor1": { - Artifacts: []ArtifactID{"file1.txt"}, + {ArtifactID: "file1.txt"}, }, }, }, then: then{ expectedError: nil, expectedJSON: `{ - "generatedAt": "2024-01-01T00:00:00Z", - "files": { - "processor1": { - "files": [ - "file1.txt" - ] - } + "generatedAt" : "2024-01-01T00:00:00Z", + "entries" : { + "processor1" : [ { + "artifactId" : "file1.txt", + "metadata" : null + } ] } }`, }, @@ -133,7 +133,7 @@ func TestJSONArtifactRegistry_Save(t *testing.T) { then: then{ expectedJSON: `{ "generatedAt": "2024-01-01T00:00:00Z", - "files": null + "entries": null }`, }, }, @@ -145,7 +145,7 @@ func TestJSONArtifactRegistry_Save(t *testing.T) { filePath := "test_registry.json" fs := &mockFileSystem{} registry := NewJSONArtifactRegistry(filePath, fs) - registry.ArtifactMap = tt.given.ArtifactMap + registry.Entries = tt.given.Entries registry.CurrentTimeProvider = func() time.Time { return time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC) } @@ -157,44 +157,44 @@ func TestJSONArtifactRegistry_Save(t *testing.T) { } else { require.NoError(t, err) } - actualJSON, err := fs.ReadFile(filePath) assert.JSONEq(t, tt.then.expectedJSON, string(actualJSON)) }) } } -func TestJSONArtifactRegistry_AddArtifact(t *testing.T) { +func TestJSONArtifactRegistry_Add(t *testing.T) { tests := []struct { name string - initialMap map[string]*JSONArtifactRegistryProcessor + initialMap map[string][]JsonArtifactRegistryEntry processorName string - artifactID ArtifactID - expectedMap map[string]*JSONArtifactRegistryProcessor + entry ArtifactRegistryEntry + expectedMap map[string][]JsonArtifactRegistryEntry }{ { name: "Add New Artifact", - initialMap: map[string]*JSONArtifactRegistryProcessor{}, + initialMap: map[string][]JsonArtifactRegistryEntry{}, processorName: "processor1", - artifactID: "file1.txt", - expectedMap: map[string]*JSONArtifactRegistryProcessor{ + entry: ArtifactRegistryEntry{ArtifactID: "file1.txt"}, + expectedMap: map[string][]JsonArtifactRegistryEntry{ "processor1": { - Artifacts: []ArtifactID{"file1.txt"}, + {ArtifactID: "file1.txt"}, }, }, }, { name: "Add Artifact to Existing Processor", - initialMap: map[string]*JSONArtifactRegistryProcessor{ + initialMap: map[string][]JsonArtifactRegistryEntry{ "processor1": { - Artifacts: []ArtifactID{"file2.txt"}, + {ArtifactID: "file2.txt"}, }, }, processorName: "processor1", - artifactID: "file1.txt", - expectedMap: map[string]*JSONArtifactRegistryProcessor{ + entry: ArtifactRegistryEntry{ArtifactID: "file1.txt"}, + expectedMap: map[string][]JsonArtifactRegistryEntry{ "processor1": { - Artifacts: []ArtifactID{"file2.txt", "file1.txt"}, + {ArtifactID: "file2.txt"}, + {ArtifactID: "file1.txt"}, }, }, }, @@ -203,68 +203,66 @@ func TestJSONArtifactRegistry_AddArtifact(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { registry := &JSONArtifactRegistry{ - ArtifactMap: tt.initialMap, + Entries: tt.initialMap, } - - // Act - registry.AddArtifact(tt.processorName, tt.artifactID) - - // Assert - assert.Equal(t, tt.expectedMap, registry.ArtifactMap) + err := registry.Add(tt.processorName, tt.entry) + require.NoError(t, err) + assert.Equal(t, tt.expectedMap, registry.Entries) }) } } -func TestJSONArtifactRegistry_RemoveArtifact(t *testing.T) { +func TestJSONArtifactRegistry_Remove(t *testing.T) { tests := []struct { name string - initialMap map[string]*JSONArtifactRegistryProcessor + initialMap map[string][]JsonArtifactRegistryEntry processorName string artifactID ArtifactID - expectedMap map[string]*JSONArtifactRegistryProcessor + expectedMap map[string][]JsonArtifactRegistryEntry }{ { name: "Remove Existing Artifact", - initialMap: map[string]*JSONArtifactRegistryProcessor{ + initialMap: map[string][]JsonArtifactRegistryEntry{ "processor1": { - Artifacts: []ArtifactID{"file1.txt", "file2.txt"}, + {ArtifactID: "file1.txt"}, + {ArtifactID: "file2.txt"}, }, }, processorName: "processor1", artifactID: "file1.txt", - expectedMap: map[string]*JSONArtifactRegistryProcessor{ + expectedMap: map[string][]JsonArtifactRegistryEntry{ "processor1": { - Artifacts: []ArtifactID{"file2.txt"}, + {ArtifactID: "file2.txt"}, }, }, }, { name: "Remove Non-Existing Artifact", - initialMap: map[string]*JSONArtifactRegistryProcessor{ + initialMap: map[string][]JsonArtifactRegistryEntry{ "processor1": { - Artifacts: []ArtifactID{"file1.txt"}, + {ArtifactID: "file1.txt"}, }, }, processorName: "processor1", artifactID: "file2.txt", - expectedMap: map[string]*JSONArtifactRegistryProcessor{ + expectedMap: map[string][]JsonArtifactRegistryEntry{ "processor1": { - Artifacts: []ArtifactID{"file1.txt"}, + {ArtifactID: "file1.txt"}, }, }, }, { name: "Remove From Non-Existing Processor", - initialMap: map[string]*JSONArtifactRegistryProcessor{ + initialMap: map[string][]JsonArtifactRegistryEntry{ "processor1": { - Artifacts: []ArtifactID{"file1.txt"}, + {ArtifactID: "file1.txt"}, }, }, processorName: "processor2", artifactID: "file1.txt", - expectedMap: map[string]*JSONArtifactRegistryProcessor{ + expectedMap: map[string][]JsonArtifactRegistryEntry{ "processor1": { - Artifacts: []ArtifactID{"file1.txt"}, + {ArtifactID: "file1.txt"}, }, }, }, @@ -273,64 +271,63 @@ func TestJSONArtifactRegistry_RemoveArtifact(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { registry := &JSONArtifactRegistry{ - ArtifactMap: tt.initialMap, + Entries: tt.initialMap, } - - // Act - registry.RemoveArtifact(tt.processorName, tt.artifactID) - - // Assert - assert.Equal(t, tt.expectedMap, registry.ArtifactMap) + err := registry.Remove(tt.processorName, tt.artifactID) + require.NoError(t, err) + assert.Equal(t, tt.expectedMap, registry.Entries) }) } } -func TestJSONArtifactRegistry_Artifacts(t *testing.T) { +func TestJSONArtifactRegistry_FindAll(t *testing.T) { tests := []struct { - name string - initialMap map[string]*JSONArtifactRegistryProcessor - processorName string - expectedArtifacts []ArtifactID + name string + initialMap map[string][]JsonArtifactRegistryEntry + processorName string + expectedEntries []ArtifactRegistryEntry }{ { - name: "Get Artifacts for Existing Processor", - initialMap: map[string]*JSONArtifactRegistryProcessor{ + name: "FindAll for Existing Processor", + initialMap: map[string][]JsonArtifactRegistryEntry{ "processor1": { - Artifacts: []ArtifactID{"file1.txt", "file2.txt"}, + {ArtifactID: "file1.txt"}, + {ArtifactID: "file2.txt"}, }, }, - processorName: "processor1", - expectedArtifacts: []ArtifactID{"file1.txt", "file2.txt"}, + processorName: "processor1", + expectedEntries: []ArtifactRegistryEntry{ + {ArtifactID: "file1.txt"}, + {ArtifactID: "file2.txt"}, + }, }, { - name: "Get Artifacts for Non-Existing Processor", - initialMap: map[string]*JSONArtifactRegistryProcessor{ + name: "FindAll for Non-Existing Processor", + initialMap: map[string][]JsonArtifactRegistryEntry{ "processor1": { - Artifacts: []ArtifactID{"file1.txt"}, + {ArtifactID: "file1.txt"}, }, }, - processorName: "processor2", - expectedArtifacts: nil, + processorName: "processor2", + expectedEntries: nil, }, { - name: "Empty Registry", - initialMap: map[string]*JSONArtifactRegistryProcessor{}, - processorName: "processor1", - expectedArtifacts: nil, + name: "Empty Registry", + initialMap: map[string][]JsonArtifactRegistryEntry{}, + processorName: "processor1", + expectedEntries: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { registry := &JSONArtifactRegistry{ - ArtifactMap: tt.initialMap, + Entries: tt.initialMap, } - // Act - artifacts := registry.Artifacts(tt.processorName) - - // Assert - assert.Equal(t, tt.expectedArtifacts, artifacts) + artifacts, err := registry.FindAll(tt.processorName) + require.NoError(t, err) + assert.Equal(t, tt.expectedEntries, artifacts) }) } } diff --git a/fileartifactprocessor.go b/fileartifactprocessor.go index 2759e24..a34fdb8 100644 --- a/fileartifactprocessor.go +++ b/fileartifactprocessor.go @@ -166,30 +166,68 @@ func (p FileArtifactProcessor) processFileArtifact(ctx ArtifactProcessingContext } if fa.WriteMode != WriteOnceMode { - ctx.AddToRegistry(fa.ID()) + meta := map[string]any{ + "path": fa.Path, + "writeMode": fa.WriteMode, + } + if err := ctx.ArtifactRegistry.Add(fa.ID(), meta); err != nil { + return err + } } return nil } func (p FileArtifactProcessor) cleanRegistry(ctx ArtifactProcessingContext) error { + var mu sync.Mutex var wg sync.WaitGroup - cleanFile := func(ctx ArtifactProcessingContext, o ArtifactID) { - defer wg.Done() - if err := p.FileSystem.Remove(string(o)); err != nil { - if errors.Is(err, os.ErrNotExist) { - return - } - panic(errors.Wrap(err, "failed cleaning artifact registry files")) - } - ctx.RemoveFromRegistry(o) + var errs errors.Group + + entries, err := ctx.ArtifactRegistry.FindAll() + if err != nil { + return err } - for _, o := range ctx.RegistryArtifacts() { + for _, entry := range entries { + if entry.Metadata == nil { + continue // TODO Error (?) + } + + writeMode, ok := entry.Metadata["writeMode"] + if !ok || writeMode != RecreateMode { + continue + } wg.Add(1) - go cleanFile(ctx, o) + go func(entry ArtifactRegistryEntry) { + defer wg.Done() + if err := p.cleanArtifact(ctx, entry); err != nil { + mu.Lock() + defer mu.Unlock() + errs = errs.Append(err) + } + }(entry) } wg.Wait() return nil } + +func (p FileArtifactProcessor) cleanArtifact(ctx ArtifactProcessingContext, entry ArtifactRegistryEntry) error { + if entry.Metadata == nil { + return nil // TODO Error (?) + } + path, ok := entry.Metadata["path"].(string) + if !ok || path == "" { + return nil + } + + if err := p.FileSystem.Remove(path); err != nil { + return err + } + + if err := ctx.ArtifactRegistry.Remove(entry.ArtifactID); err != nil { + return err + } + + return nil +} diff --git a/fileartifactprocessor_test.go b/fileartifactprocessor_test.go index 9897b9e..a894bd8 100644 --- a/fileartifactprocessor_test.go +++ b/fileartifactprocessor_test.go @@ -66,11 +66,14 @@ func TestWriteFileArtifactProcessor_Process(t *testing.T) { t.Run(tt.name, func(t *testing.T) { processor := FileArtifactProcessor{FileSystem: tt.mockFS} ctx := ArtifactProcessingContext{ - Context: context.Background(), - Artifacts: tt.artifacts, - Logger: NewDefaultLogger(DefaultLoggerConfig{}), - artifactRegistry: &InMemoryArtifactRegistry{}, - processorName: processor.Name(), + Context: context.Background(), + Artifacts: tt.artifacts, + Logger: NewDefaultLogger(DefaultLoggerConfig{}), + ArtifactRegistry: ProcessorArtifactRegistry{ + processorName: "unit_tester", + registry: &InMemoryArtifactRegistry{}, + }, + processorName: processor.Name(), } err := processor.Process(ctx) diff --git a/processing.go b/processing.go index 8771bc3..1c8dce4 100644 --- a/processing.go +++ b/processing.go @@ -59,59 +59,80 @@ type ArtifactRegistry interface { // error occurs, it should be returned to indicate the failure of the saving operation. Save() error - // AddArtifact registers an ArtifactID under a specific processor name. This method + // Add registers an ArtifactID under a specific processor name. This method // should ensure that the file path is associated with the given processor name // in the registry. - AddArtifact(processorName string, artifactID ArtifactID) + Add(processorName string, e ArtifactRegistryEntry) error - // RemoveArtifact removes a given ArtifactID artifact registration for a specific processor name. This + // Remove a given ArtifactID artifact registration for a specific processor name. This // method should ensure that the file path is disassociated from the given // processor name in the registry. - RemoveArtifact(processorName string, artifactID ArtifactID) + Remove(processorName string, artifactID ArtifactID) error - // Artifacts returns the artifacts for a given processor. - Artifacts(processorName string) []ArtifactID + // FindByID finds an entry by its ArtifactID. + FindByID(processorName string, artifactID ArtifactID) (entry ArtifactRegistryEntry, found bool, err error) + + // FindAll returns all the entries in the registry. + FindAll(processorName string) ([]ArtifactRegistryEntry, error) } -type NoopArtifactRegistry struct { +type ArtifactRegistryEntry struct { + ArtifactID ArtifactID + Metadata map[string]any } -func (n NoopArtifactRegistry) Load() error { - return nil +var _ ArtifactRegistry = NoopArtifactRegistry{} + +type NoopArtifactRegistry struct{} + +func (n NoopArtifactRegistry) Add(processorName string, e ArtifactRegistryEntry) error { return nil } + +func (n NoopArtifactRegistry) Remove(processorName string, artifactID ArtifactID) error { return nil } + +func (n NoopArtifactRegistry) FindByID(processorName string, artifactID ArtifactID) (_ ArtifactRegistryEntry, _ bool, _ error) { + return ArtifactRegistryEntry{}, false, nil } -func (n NoopArtifactRegistry) Save() error { - return nil +func (n NoopArtifactRegistry) FindAll(processorName string) ([]ArtifactRegistryEntry, error) { + return nil, nil } -func (n NoopArtifactRegistry) AddArtifact(_ string, _ ArtifactID) {} +func (n NoopArtifactRegistry) Load() error { return nil } -func (n NoopArtifactRegistry) RemoveArtifact(_ string, _ ArtifactID) {} +func (n NoopArtifactRegistry) Save() error { return nil } -func (n NoopArtifactRegistry) Artifacts(_ string) []ArtifactID { - return nil +type ProcessorArtifactRegistry struct { + processorName string + registry ArtifactRegistry } -type ArtifactProcessingContext struct { - context.Context - Specifications SpecificationGroup - Artifacts []Artifact - Logger Logger +func (n ProcessorArtifactRegistry) Add(artifactID ArtifactID, metadata map[string]any) error { + return n.registry.Add(n.processorName, ArtifactRegistryEntry{ + ArtifactID: artifactID, + Metadata: metadata, + }) +} - artifactRegistry ArtifactRegistry - processorName string +func (n ProcessorArtifactRegistry) Remove(artifactID ArtifactID) error { + return n.registry.Remove(n.processorName, artifactID) } -func (c *ArtifactProcessingContext) AddToRegistry(artifactID ArtifactID) { - c.artifactRegistry.AddArtifact(c.processorName, artifactID) +func (n ProcessorArtifactRegistry) FindByID(artifactID ArtifactID) (_ ArtifactRegistryEntry, _ bool, _ error) { + return n.registry.FindByID(n.processorName, artifactID) } -func (c *ArtifactProcessingContext) RemoveFromRegistry(artifactID ArtifactID) { - c.artifactRegistry.RemoveArtifact(c.processorName, artifactID) +func (n ProcessorArtifactRegistry) FindAll() ([]ArtifactRegistryEntry, error) { + return n.registry.FindAll(n.processorName) } -func (c *ArtifactProcessingContext) RegistryArtifacts() []ArtifactID { - return c.artifactRegistry.Artifacts(c.processorName) +type ArtifactProcessingContext struct { + context.Context + Specifications SpecificationGroup + Artifacts []Artifact + Logger Logger + + ArtifactRegistry ProcessorArtifactRegistry + processorName string } // ArtifactProcessor are services responsible for processing artifacts of SpecProcessors. diff --git a/processing_test.go b/processing_test.go index 1f0e8c0..2ffa39c 100644 --- a/processing_test.go +++ b/processing_test.go @@ -3,6 +3,7 @@ package specter import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" "testing" ) @@ -21,11 +22,11 @@ func (m *MockArtifactRegistry) Save() error { return args.Error(0) } -func (m *MockArtifactRegistry) AddArtifact(processorName string, artifactID ArtifactID) { +func (m *MockArtifactRegistry) Add(processorName string, artifactID ArtifactID) { m.Called(processorName, artifactID) } -func (m *MockArtifactRegistry) RemoveArtifact(processorName string, artifactID ArtifactID) { +func (m *MockArtifactRegistry) Remove(processorName string, artifactID ArtifactID) { m.Called(processorName, artifactID) } @@ -34,64 +35,6 @@ func (m *MockArtifactRegistry) Artifacts(processorName string) []ArtifactID { return args.Get(0).([]ArtifactID) } -func TestArtifactProcessingContext__AddToRegistry(t *testing.T) { - // Arrange - mockRegistry := &MockArtifactRegistry{} - ctx := &ArtifactProcessingContext{ - artifactRegistry: mockRegistry, - processorName: "testProcessor", - } - - artifactID := ArtifactID("artifactFile.txt") - - mockRegistry.On("AddArtifact", "testProcessor", artifactID).Return() - - // Act - ctx.AddToRegistry(artifactID) - - // Assert - mockRegistry.AssertExpectations(t) -} - -func TestArtifactProcessingContext__RemoveFromRegistry(t *testing.T) { - // Arrange - mockRegistry := new(MockArtifactRegistry) - ctx := &ArtifactProcessingContext{ - artifactRegistry: mockRegistry, - processorName: "testProcessor", - } - - artifactID := ArtifactID("artifactFile.txt") - - mockRegistry.On("RemoveArtifact", "testProcessor", artifactID).Return() - - // Act - ctx.RemoveFromRegistry(artifactID) - - // Assert - mockRegistry.AssertExpectations(t) -} - -func TestArtifactProcessingContext__RegistryArtifacts(t *testing.T) { - // Arrange - mockRegistry := new(MockArtifactRegistry) - ctx := &ArtifactProcessingContext{ - artifactRegistry: mockRegistry, - processorName: "testProcessor", - } - - expectedArtifacts := []ArtifactID{"file1.txt", "file2.txt"} - - mockRegistry.On("Artifacts", "testProcessor").Return(expectedArtifacts) - - // Act - artifacts := ctx.RegistryArtifacts() - - // Assert - assert.Equal(t, expectedArtifacts, artifacts) - mockRegistry.AssertExpectations(t) -} - func TestNoopArtifactRegistry_Load(t *testing.T) { // Arrange registry := NoopArtifactRegistry{} @@ -114,35 +57,21 @@ func TestNoopArtifactRegistry_Save(t *testing.T) { assert.NoError(t, err, "Save should not return an error") } -func TestNoopArtifactRegistry_AddArtifact(t *testing.T) { - // Arrange +func TestNoopArtifactRegistry_Add(t *testing.T) { registry := NoopArtifactRegistry{} - - // Act - registry.AddArtifact("processor1", "artifactFile.txt") - - // Assert - // No state to assert since it's a no-op, just ensure it doesn't panic or error. + err := registry.Add("processor1", ArtifactRegistryEntry{}) + require.NoError(t, err) } -func TestNoopArtifactRegistry_RemoveArtifact(t *testing.T) { - // Arrange +func TestNoopArtifactRegistry_Remove(t *testing.T) { registry := NoopArtifactRegistry{} - - // Act - registry.RemoveArtifact("processor1", "artifactFile.txt") - - // Assert - // No state to assert since it's a no-op, just ensure it doesn't panic or error. + err := registry.Remove("processor1", "artifactFile.txt") + require.NoError(t, err) } -func TestNoopArtifactRegistry_Artifacts(t *testing.T) { - // Arrange +func TestNoopArtifactRegistry_FindAll(t *testing.T) { registry := NoopArtifactRegistry{} - - // Act - artifacts := registry.Artifacts("processor1") - - // Assert - assert.Nil(t, artifacts, "Artifacts should return nil for NoopArtifactRegistry") + artifacts, err := registry.FindAll("processor1") + require.NoError(t, err) + require.Nil(t, artifacts, "FindAll should return nil for NoopArtifactRegistry") } diff --git a/specter.go b/specter.go index 3f8a8fd..aa764ba 100644 --- a/specter.go +++ b/specter.go @@ -244,16 +244,19 @@ func (s Specter) ProcessArtifacts(ctx context.Context, specifications []Specific return err } - octx := ArtifactProcessingContext{ - Context: ctx, - Specifications: specifications, - Artifacts: artifacts, - Logger: s.Logger, - artifactRegistry: s.ArtifactRegistry, - processorName: p.Name(), + artifactCtx := ArtifactProcessingContext{ + Context: ctx, + Specifications: specifications, + Artifacts: artifacts, + Logger: s.Logger, + ArtifactRegistry: ProcessorArtifactRegistry{ + processorName: p.Name(), + registry: s.ArtifactRegistry, + }, + processorName: p.Name(), } - err := p.Process(octx) + err := p.Process(artifactCtx) if err != nil { return errors.WrapWithMessage(err, errors.InternalErrorCode, fmt.Sprintf("artifact processor %q failed", p.Name())) } @@ -263,7 +266,7 @@ func (s Specter) ProcessArtifacts(ctx context.Context, specifications []Specific return fmt.Errorf("failed saving artifact registry: %w", err) } - s.Logger.Success("Artifacts processed successfully.") + s.Logger.Success("FindAll processed successfully.") return nil } diff --git a/specter_test.go b/specter_test.go index 126f626..4a4cb69 100644 --- a/specter_test.go +++ b/specter_test.go @@ -7,7 +7,7 @@ import ( func TestWithArtifactRegistry(t *testing.T) { s := &Specter{} - r := &JSONArtifactRegistry{} + r := &NoopArtifactRegistry{} WithArtifactRegistry(r)(s) assert.Equal(t, r, s.ArtifactRegistry) }