File kube-kompare-0.0.2~alpha3.obscpio of Package kube-kompare

07070100000000000041ED00000000000000000000000265DC12FD00000000000000000000000000000000000000000000002200000000kube-kompare-0.0.2~alpha3/.github07070100000001000041ED00000000000000000000000265DC12FD00000000000000000000000000000000000000000000003100000000kube-kompare-0.0.2~alpha3/.github/ISSUE_TEMPLATE07070100000002000081A400000000000000000000000165DC12FD00000342000000000000000000000000000000000000003F00000000kube-kompare-0.0.2~alpha3/.github/ISSUE_TEMPLATE/bug_report.md---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Desktop (please complete the following information):**
 - OS: [e.g. iOS]
 - Browser [e.g. chrome, safari]
 - Version [e.g. 22]

**Smartphone (please complete the following information):**
 - Device: [e.g. iPhone6]
 - OS: [e.g. iOS8.1]
 - Browser [e.g. stock browser, safari]
 - Version [e.g. 22]

**Additional context**
Add any other context about the problem here.
07070100000003000081A400000000000000000000000165DC12FD0000007E000000000000000000000000000000000000003B00000000kube-kompare-0.0.2~alpha3/.github/ISSUE_TEMPLATE/custom.md---
name: Custom issue template
about: Describe this issue template's purpose here.
title: ''
labels: ''
assignees: ''

---


07070100000004000081A400000000000000000000000165DC12FD00000253000000000000000000000000000000000000004400000000kube-kompare-0.0.2~alpha3/.github/ISSUE_TEMPLATE/feature_request.md---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.
07070100000005000041ED00000000000000000000000265DC12FD00000000000000000000000000000000000000000000002C00000000kube-kompare-0.0.2~alpha3/.github/workflows07070100000006000081A400000000000000000000000165DC12FD00000311000000000000000000000000000000000000003300000000kube-kompare-0.0.2~alpha3/.github/workflows/go.yml# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go

name: Go

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

jobs:

  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3

    - name: Set up Go
      uses: actions/setup-go@v4
      with:
        go-version: '1.21.x'

    - name: Cache dependencies
      uses: actions/cache@v4
      with:
        path: |
          .go/cache
          ./gen
        key: ${{ runner.os }}-${{ hashFiles('./go.mod') }}

    - name: Test
      run: go test -v ./... -cover

    - name: linter
      uses: golangci/golangci-lint-action@v4

    # - name: Build
    #   run: go build -v ./...
07070100000007000081A400000000000000000000000165DC12FD0000000A000000000000000000000000000000000000002500000000kube-kompare-0.0.2~alpha3/.gitignore__debug_*
07070100000008000041ED00000000000000000000000265DC12FD00000000000000000000000000000000000000000000002200000000kube-kompare-0.0.2~alpha3/.vscode07070100000009000081A400000000000000000000000165DC12FD00000561000000000000000000000000000000000000002E00000000kube-kompare-0.0.2~alpha3/.vscode/launch.json// {
//     // Use IntelliSense to learn about possible attributes.
//     // Hover to view descriptions of existing attributes.
//     // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
//     "version": "0.2.0",
//     "configurations": [
//         {
//             "name": "Launch Package",
//             "type": "go",
//             "request": "launch",
//             "mode": "auto",
//             "program": "${fileDirname}",
//             "console": "integratedTerminal",
//             "args": [
//                 "test",
//             ]
//         }
//     ]
// }

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch Package",
            "type": "go",
            "request": "launch",
            "mode": "auto",
            "program": "${fileDirname}",
            "console": "integratedTerminal",
            "args": [
                "-t",
                "some-context",
                "-n",
                "invoice-live-pci",
                "-vv",
                "-i",
                "hpa",
                // "-f",
                // "CreationTimestamp"
            ]
        }
    ]
}0707010000000A000081A400000000000000000000000165DC12FD00000DCE000000000000000000000000000000000000002A00000000kube-kompare-0.0.2~alpha3/CONTRIBUTING.md# Kompare Contributor's Guide
Thank you for considering contributing to Kompare! This guide outlines how you can contribute to the project effectively.

# Before Contributing
Before diving into contributions, please take note of the following:

1. We encourge you to create an Issue: Before starting work on a new feature, bug fix, or any significant change, create an issue to discuss it with the maintainers and the community. This ensures alignment with project goals and prevents duplication of effort, etc.
2. Understanding the Project: Familiarize yourself with the project's purpose, functionality, and goals by reading the README and exploring the source code.
3. Reviewing Existing Issues: Check the existing issues on the project's repository to see if there are any open tasks, bugs, or feature requests that align with your interests or expertise.
4. Coding Standards: Adhere to the project's coding standards and guidelines. If there are none specified, maintain consistency with the existing codebase.

# Getting Started
To contribute to Kompare, follow these steps:

Fork the Repository: Fork the Kompare repository to your GitHub account.

Clone the Repository: Clone your forked repository to your local machine.

```
git clone https://github.com/your-username/kompare.git
```
Create a Branch: Create a new branch for your contribution. Use a descriptive name that summarizes the purpose of your changes.
```
git checkout -b feature/your-feature-name
```

Make Changes: Implement your changes or additions to the project. Ensure your code is well-documented and follows best practices.

Test Your Changes: Before submitting a pull request, test your changes locally to ensure they function as expected and do not introduce any regressions.

Commit Your Changes: Commit your changes with clear and concise commit messages.

```
git commit -m "Add feature: Brief description of your changes"
```
Push Changes: Push your commits to your forked repository.
```
git push origin feature/your-feature-name
```
Submit a Pull Request: Once you have pushed your changes to your fork, submit a pull request to the main Kompare repository. Provide a detailed description of your changes and reference the related issue(s) if applicable.

# Main Contribution Areas
Here are the main areas where contributions are particularly welcome, but feel free to suggest diferently:
1. Adding Test Cases: Help improve test coverage by adding comprehensive test cases for existing and new functionality.
2. Enhancing Visualization: Improve the visualization and summary view for better user experience and understanding of differences.
3. Addressing Issues and Bugs: Participate in issue resolution by identifying, reporting, and fixing bugs or addressing existing issues.
4. Documentation: Enhance project documentation, including README, code comments, and user guides, to make it more accessible and informative.

# Discussion and Other Issues
If you have ideas, questions, or concerns that are not covered by existing issues, feel free to create new issues to discuss them with the community and the maintainers. Collaboration and open communication are key to driving the project forward.

All contributions are subject to code review by project maintainers. Be open to feedback and constructive criticism during the review process. Collaboration and respectful communication are key to maintaining a healthy and productive open-source community.

Thank you for considering contributing to Kompare! Your efforts are greatly appreciated.
0707010000000B000041ED00000000000000000000000265DC12FD00000000000000000000000000000000000000000000001E00000000kube-kompare-0.0.2~alpha3/DAO0707010000000C000081A400000000000000000000000165DC12FD000000CD000000000000000000000000000000000000002500000000kube-kompare-0.0.2~alpha3/DAO/DAO.gopackage DAO

type DiffWithName struct {
	Name           string
	Namespace      string
	Diff           []string
	PropertyName   string
	MessageHeading string
	SourceMessage  string
	TargetMessage  string
}
0707010000000D000081A400000000000000000000000165DC12FD0000053B000000000000000000000000000000000000002A00000000kube-kompare-0.0.2~alpha3/DAO/DAO_test.gopackage DAO

import (
	"testing"
)

func TestDiffWithName(t *testing.T) {
	// Initialize a DiffWithName instance
	diff := DiffWithName{
		Name:           "TestName",
		Namespace:      "TestNamespace",
		Diff:           []string{"diff1", "diff2"},
		PropertyName:   "TestProperty",
		MessageHeading: "TestHeading",
		SourceMessage:  "SourceMessage",
		TargetMessage:  "TargetMessage",
	}

	// Assert that the fields are set correctly
	if diff.Name != "TestName" {
		t.Errorf("Expected Name to be 'TestName', got %s", diff.Name)
	}
	if diff.Namespace != "TestNamespace" {
		t.Errorf("Expected Namespace to be 'TestNamespace', got %s", diff.Namespace)
	}
	if len(diff.Diff) != 2 || diff.Diff[0] != "diff1" || diff.Diff[1] != "diff2" {
		t.Errorf("Expected Diff to be ['diff1', 'diff2'], got %v", diff.Diff)
	}
	if diff.PropertyName != "TestProperty" {
		t.Errorf("Expected PropertyName to be 'TestProperty', got %s", diff.PropertyName)
	}
	if diff.MessageHeading != "TestHeading" {
		t.Errorf("Expected MessageHeading to be 'TestHeading', got %s", diff.MessageHeading)
	}
	if diff.SourceMessage != "SourceMessage" {
		t.Errorf("Expected SourceMessage to be 'SourceMessage', got %s", diff.SourceMessage)
	}
	if diff.TargetMessage != "TargetMessage" {
		t.Errorf("Expected TargetMessage to be 'TargetMessage', got %s", diff.TargetMessage)
	}
}
0707010000000E000081A400000000000000000000000165DC12FD00000236000000000000000000000000000000000000002500000000kube-kompare-0.0.2~alpha3/Dockerfile# Start from the official golang image
FROM golang:1.21

# Set the Current Working Directory inside the container
WORKDIR /app

# Copy go mod and sum files
COPY go.mod go.sum ./

# Download all dependencies. Dependencies will be cached if the go.mod and go.sum files are not changed
RUN go mod download

# Copy the source code from the current directory to the Working Directory inside the container
COPY . .

# Build the Go app
RUN go build -o kompare .

# Expose port 8080 to the outside world
EXPOSE 8080

# Command to run the executable
ENTRYPOINT ["./kompare"]
0707010000000F000081A400000000000000000000000165DC12FD00002C5D000000000000000000000000000000000000002200000000kube-kompare-0.0.2~alpha3/LICENSE
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.07070100000010000081A400000000000000000000000165DC12FD00001C1C000000000000000000000000000000000000002400000000kube-kompare-0.0.2~alpha3/README.md# Kompare

Kompare is a Go CLI runner for comparing two clusters. This software compares two Kubernetes clusters using kubeconfig to connect to them and compare existing objects in the two clusters based on flexible criteria passed via the command line.

When comparing two Kubernetes clusters, you may encounter challenges such as ignoring Kubernetes resource definition subtypes like UID and dates, or filtering and comparing only specific types of objects. Existing tools may not offer the flexibility to define such criteria, which led us to create Kompare.

![Kompare: Simplifying Kubernetes Cluster Comparison](https://miro.medium.com/v2/resize:fit:1400/1*oOPoArcHhU26oM0iUuGjAA.png)

## Why Do We Need Kompare

This CLI tool is designed to compare two clusters to determine if they are different or if they can be interchangeable. Enterprises often maintain multiple Kubernetes clusters for redundancy or to facilitate upgrades. We primarily use this tool to compare a production cluster (source cluster) with a new cluster intended for production use or to run side by side.

**Notice:** The source cluster is typically considered the source of truth for the comparison.

## Key Terms & Usage

1. **Source cluster:** The original cluster, analogous to the "left-hand side" (LHS) in a number comparison.
2. **Target cluster:** The destination cluster, analogous to the "right-hand side" (RHS) or the "second number" in a number comparison.

## Getting Started
You can run it by building out directly with go if you have golang installed:
```
$ git clone https://github.com/xendit/kompare.git
$ cd kompare
$ go build -o kompare .
$ ./kompare -h
usage: print [-h|--help] [-c|--conf "<value>"] [-s|--src "<value>"] -t|--target
             "<value>" [-v|--verbose] [-i|--include "<value>"] [-e|--exclude
             "<value>"] [-n|--namespace "<value>"] [-f|--filter "<value>"]

             Prints provided string to stdout

Arguments:

  -h  --help       Print help information
  -c  --conf       Path to the clusters kubeconfig; assume ~/.kube/config if
                   not provided
  -s  --src        The Source cluster's context. Origin cluster in the
                   comparison (LHS-left hand side)
  -t  --target     *The target cluster's context (Required). Cluster used as
                   destination or consequent (RHS - Right hand side)
  -v  --verbose    -v lists the differences and -vv just shows all the diffs
                   too.
  -i  --include    List of kubernetes objects names to include, this should be
                   an element or a comma separated list.
  -e  --exclude    List of kubernetes objects to include, this should be an
                   element or a comma separated list.
  -n  --namespace  Namespace that needs to be copied. defaults to 'default'
                   namespace. The option also accepts wilcard matching of
                   namespace. E.G.: '*-pci' would match any namespace that ends
                   with -pci. Notice that the '' might be required in some
                   consoles like iterm
  -f  --filter     Filter what parts of the object I want to compare. must be
                   used together with -i option to apply to that type of
                   objects
$
```

To run directly with golang if you have it installed:
```
$ git clone https://github.com/xendit/kompare.git
$ cd kompare
$ go run main.go -h
(...)
```

### Using the software to compare two kubernetes clusters:
Notice: The only option requires is -t.

This project is currently in development. To use it, either build it with Go or run it directly from the console:

```
./kompare -t some-target-context.
```
The command with go would be `go run main.go -t some-target-context`.

see [this introductory post](https://blog.xendit.engineer/kompare-simplifying-kubernetes-cluster-comparison-ced2792716d9) for mode details. 
### Example Command

To compare the current context with "MySecondContext-Cluster", and view the differences using the `-v` (verbose see the help `-vv`) option, also in this case we are using `namespace kube-system` and we only want the `deployments`:

```
./kompare -t MySecondContext-Cluster  -v -n kube-system -i deploy
We will use current kubeconfig context as 'source cluster'.
We will use MySecondContext-Cluster kubeconfig context as 'target cluster'.
Using kube-system namespace
Looping namespace: kube-system
Deployment
******************************************************************************************************
- First cluster has Deployment in the list: blackbox-controller, but it's not in the second cluster

******************************************************************************************************
- Second cluster has Deployment in the list: aws-load-balancer-controller, but it's not in the first cluster

******************************************************************************************************
Finished Deployment for namespace: kube-system
Finished all comparison works!
```

Another example, we use velero for backups and want to see if both clusters have the same version deployed:
```
./kompare -t MySecondContext-Cluster -vv -n velero -i deploy
We will use current kubeconfig context as 'source cluster'.
We will use arn:aws:eks:ap-southeast-3:705506614808:cluster/xnd-jk-stg-aws-2 kubeconfig context as 'target cluster'.
Using velero namespace
Looping namespace: velero
Deployment
******************************************************************************************************
Done compering source cluster versus target cluster's  Deployment in the list
Done compering target cluster versus source cluster's  Deployment in the list
No differences found; Object Name velero, Kubernetes resource definition type Name, Namespace velero
Kubernetes resource definition type: Spec.Template.Spec
Object Name: velero
Namespace: velero
Differences:
- Containers.slice[0].Image: velero/velero:v1.12.2 != velero/velero:v1.9.2
- Containers.slice[0].Args.slice[1]: --uploader-type=restic != <no value>
- Containers.slice[0].LivenessProbe: v1.Probe != <nil pointer>
- Containers.slice[0].ReadinessProbe: v1.Probe != <nil pointer>
- TerminationGracePeriodSeconds: 3600 != 30


Finished Deployment for namespace: velero
Finished all comparison works!
```

**Notice:** The software assumes the current context as the source cluster by default (use `-s` or `--source` to set a different source context). The `-t` option specifies the destination/target cluster in your comparison. If it was number comparison -s is LHS and -t is RHS.

**Notice:** The source cluster is typically considered the source of truth for the comparison in Kompare.

### Prerequisites

Kompare is written in Go and has been tested on Mac Silicon Processors. It should work on other architectures and operating systems as well. Ensure you have Go 1.21.6 or higher installed.

## Contributing

Contributions such as pull requests, testing, and issue reporting are welcome. Current focus areas include:

1. Adding more and better test cases.
2. Improving visualization, particularly the summary view.
3. Enhancing visualizations for differences in verbose mode.
4. Addressing issues and bugs.

07070100000011000041ED00000000000000000000000265DC12FD00000000000000000000000000000000000000000000001E00000000kube-kompare-0.0.2~alpha3/cli07070100000012000081A400000000000000000000000165DC12FD00002D0C000000000000000000000000000000000000002800000000kube-kompare-0.0.2~alpha3/cli/parser.gopackage cli

import (
	"fmt"
	"kompare/tools"
	"os"
	"path"

	"github.com/akamensky/argparse"
)

type ArgumentsReceived struct {
	KubeconfigFile, SourceClusterContext, TargetClusterContext, NamespaceName, FiltersForObject, Include, Exclude *string
	VerboseDiffs                                                                                                  *int
	FileOutput                                                                                                    *string
	Err                                                                                                           error
}
type ArgumentsReceivedValidated struct {
	KubeconfigFile, SourceClusterContext, TargetClusterContext, NamespaceName, FiltersForObject string
	Include, Exclude                                                                            []string
	VerboseDiffs                                                                                int
	FileOutput                                                                                  string
	Err                                                                                         error
}

// PaserReader parses the command-line arguments and returns validated arguments.
// It creates a new parser object and defines various flags and options.
// The flags and options include:
//   - 'c' or 'conf' flag for specifying the path to the kubeconfig file (optional).
//   - 's' or 'src' flag for specifying the source cluster's context (optional).
//   - 't' or 'target' flag for specifying the target cluster's context (required).
//   - 'v' or 'verbose' flag for enabling verbose mode to show all diffs (optional).
//   - 'i' or 'include' flag for specifying a list of Kubernetes objects to include (optional).
//   - 'e' or 'exclude' flag for specifying a list of Kubernetes objects to exclude (optional).
//   - 'n' or 'namespace' flag for specifying the namespace to be copied (optional, defaults to 'default').
//   - 'f' or 'filter' flag for specifying what parts of the object to compare (optional).
//
// If an error occurs during parsing, it prints the error and usage information.
// The function returns a struct containing validated arguments.
func PaserReader() ArgumentsReceivedValidated {
	// Create new parser object
	parser := argparse.NewParser("print", "Prints provided string to stdout")
	kubeconfigFile := parser.String("c", "conf", &argparse.Options{Required: false, Help: "Path to the clusters kubeconfig; assume ~/.kube/config if not provided"})
	sourceClusterContext := parser.String("s", "src", &argparse.Options{Required: false, Help: "The Source cluster's context. Origin cluster in the comparison (LHS-left hand side)"})
	targetClusterContext := parser.String("t", "target", &argparse.Options{Required: true, Help: "*The target cluster's context (Required). Cluster used as destination or consequent (RHS - Right hand side)"})
	verboseDiffs := parser.FlagCounter("v", "verbose", &argparse.Options{Help: "-v lists the differences and -vv just shows all the diffs too."})
	IncludeK8sObjects := parser.String("i", "include", &argparse.Options{Help: "List of kubernetes objects names to include, this should be an element or a comma separated list."})
	Excludek8sObjects := parser.String("e", "exclude", &argparse.Options{Help: "List of kubernetes objects to include, this should be an element or a comma separated list."})
	namespaceName := parser.String("n", "namespace", &argparse.Options{Help: "Namespace that needs to be copied. defaults to 'default' namespace. The option also accepts wilcard matching of namespace. E.G.: '*-pci' would match any namespace that ends with -pci. Notice that the '' might be required in some consoles like iterm"})
	filtersForObject := parser.String("f", "filter", &argparse.Options{Help: "Filter what parts of the object I want to compare. must be used together with -i option to apply to that type of objects"})
	fileOutput := parser.String("l", "file", &argparse.Options{Required: false, Help: "Save the output to a file. If not provided, the output will be printed to the console."})
	err := parser.Parse(os.Args)
	if err != nil {
		// In case of error print error and print usage
		// This can also be done by passing -h or --help flags
		fmt.Print(parser.Usage(err))
		return ArgumentsReceivedValidated{
			KubeconfigFile:       "",
			SourceClusterContext: "",
			TargetClusterContext: "",
			NamespaceName:        "",
			FiltersForObject:     "",
			Include:              []string{""},
			Exclude:              []string{""},
			VerboseDiffs:         *verboseDiffs,
			FileOutput:           "",
			Err:                  err}
	}
	TheArgs := ArgumentsReceived{
		KubeconfigFile:       kubeconfigFile,
		SourceClusterContext: sourceClusterContext,
		TargetClusterContext: targetClusterContext,
		NamespaceName:        namespaceName,
		Include:              IncludeK8sObjects,
		Exclude:              Excludek8sObjects,
		FiltersForObject:     filtersForObject,
		VerboseDiffs:         verboseDiffs,
		FileOutput:           fileOutput,
		Err:                  err}
	ArgumentsReceivedValidated := ValidateParametersFromParserArgs(TheArgs)
	return ArgumentsReceivedValidated
}

// ValidateParametersFromParserArgs validates the arguments received from the command-line parser.
// It extracts the source cluster context, target cluster context, and namespace name from the arguments.
// If the source cluster context is empty, it informs the user that the current kubeconfig context will be used.
// If not empty, it informs the user about the source cluster context being used.
// It sets the kubeconfig file path based on the provided file path or the default ~/.kube/config.
// It validates and parses the include and exclude lists of Kubernetes objects.
// If there are invalid objects in the include or exclude lists, it prints a warning but continues execution.
// It checks for improper usage of filtering options with include and exclude lists and prints warnings accordingly.
// The function returns a struct containing validated arguments for further processing.
func ValidateParametersFromParserArgs(TheArgs ArgumentsReceived) ArgumentsReceivedValidated {
	var strSourceClusterContext, strTargetClusterContext, strNamespaceName string
	strSourceClusterContext = *TheArgs.SourceClusterContext
	strTargetClusterContext = *TheArgs.TargetClusterContext
	if strSourceClusterContext == "" {
		fmt.Println("We will use current kubeconfig context as 'source cluster'.")
	} else {
		fmt.Printf("We will use %s kubeconfig context as 'source cluster' or 'origin cluster'.\n", strSourceClusterContext)
	}
	fmt.Printf("We will use %s kubeconfig context as 'target cluster'.\n", strTargetClusterContext)

	strNamespaceName = *TheArgs.NamespaceName
	configFile := ""
	if *TheArgs.KubeconfigFile != "" {
		configFile = *TheArgs.KubeconfigFile
	} else {
		homeDir, err := os.UserHomeDir()
		if err != nil {
			fmt.Printf("Error getting the home dir: %v\n", err)
			return ArgumentsReceivedValidated{
				KubeconfigFile: "", SourceClusterContext: "",
				TargetClusterContext: "", NamespaceName: "",
				FiltersForObject: "",
				Include:          []string{""}, Exclude: []string{""},
				VerboseDiffs: *TheArgs.VerboseDiffs, Err: nil}
		}
		configFile = path.Join(homeDir, ".kube", "config")
	}
	invalidInclude, includeStr := ValidateKubernetesObjects(tools.ParseCommaSeparateList(*TheArgs.Include))
	invalidExclude, excludeStr := ValidateKubernetesObjects(tools.ParseCommaSeparateList(*TheArgs.Exclude))

	if invalidInclude != nil {
		fmt.Print("You passed some invalid kubernetes object to incldue as a parameter: ", invalidInclude)
		fmt.Println(". The program will try to execute anyways and ignore this")
	}
	if invalidExclude != nil {
		fmt.Println("You passed some invalid kubernetes object to exclude as a parameter: ", invalidInclude)
		fmt.Println(". The program will try to execute anyways and ignore this")
	}
	if *TheArgs.FiltersForObject != "" && *TheArgs.Exclude != "" {
		fmt.Println("Warning: The -f filtering option was not designed to be used with the -e option.")
		fmt.Println("The program will try to execute anyway, but the output might not be what you expect.")
		fmt.Println("The -f is to be used with one and only one -i include object type at the time.")
	}
	if *TheArgs.FiltersForObject != "" && tools.HasCharacter(*TheArgs.Include, ',') {
		fmt.Println("Warning: The -f filtering option was not designed to be used with multiple -i objects,")
		fmt.Println("The program will try to execute anyway, but the output might not be what you expect.")
		fmt.Println("The -f is to be used with one and only one -i include object type at the time.")
	}
	file := *TheArgs.FileOutput
	if file != "" {
		valid, filePath, err := tools.IsValidPath(file)
		if err == nil {
			if valid {
				fmt.Printf("The output will be saved to the file: %s\n", filePath)
			}
		} else {
			fmt.Println(err)
		}
		return ArgumentsReceivedValidated{
			KubeconfigFile:       configFile,
			SourceClusterContext: strSourceClusterContext,
			TargetClusterContext: strTargetClusterContext,
			NamespaceName:        strNamespaceName,
			FiltersForObject:     *TheArgs.FiltersForObject,
			Include:              includeStr,
			Exclude:              excludeStr,
			VerboseDiffs:         *TheArgs.VerboseDiffs,
			FileOutput:           filePath,
			Err:                  nil}
	}
	return ArgumentsReceivedValidated{
		KubeconfigFile:       configFile,
		SourceClusterContext: strSourceClusterContext,
		TargetClusterContext: strTargetClusterContext,
		NamespaceName:        strNamespaceName,
		FiltersForObject:     *TheArgs.FiltersForObject,
		Include:              includeStr,
		Exclude:              excludeStr,
		VerboseDiffs:         *TheArgs.VerboseDiffs,
		FileOutput:           "",
		Err:                  nil}
}

// ValidateKubernetesObjects validates the given list of Kubernetes object names
// against a list of valid object names and their aliases
// It returns two slices: invalidObjects and validObjects
func ValidateKubernetesObjects(objects []string) ([]string, []string) {
	validObjects := map[string][]string{
		"deployment":         {"deployment", "deployments", "deploy"},
		"ingress":            {"ingress", "ing"},
		"service":            {"service", "svc", "services"},
		"serviceaccount":     {"sa", "serviceaccount", "serviceaccounts"},
		"configmap":          {"configmap", "configmaps", "cm"},
		"secret":             {"secret", "secrets"},
		"namespace":          {"namespace", "ns", "namespaces"},
		"hpa":                {"hpa", "horizontalpodautoscaler", "horizontalpodautoscalers", "hpas"},
		"role":               {"role", "roles"},
		"rolebinding":        {"rolebinding", "rolebindings"},
		"clusterrole":        {"clusterrole", "clusterroles"},
		"clusterrolebinding": {"clusterrolebinding", "clusterrolebindings"},
		"crd":                {"crd", "crds", "customresourcedefinition", "customresourcedefinitions"},
		"networkpolicy":      {"networkpolicy", "networkpolicies"},
		// Add more valid objects and their aliases as needed
	}

	var invalidObjects []string
	var validObjectsStr []string

	for _, obj := range objects {
		found := false
		for standardName, aliases := range validObjects {
			for _, alias := range aliases {
				if obj == alias {
					found = true
					validObjectsStr = append(validObjectsStr, standardName)
					break
				}
			}
			if found {
				break
			}
		}
		if !found {
			invalidObjects = append(invalidObjects, obj)
		}
	}
	return invalidObjects, validObjectsStr
}
07070100000013000081A400000000000000000000000165DC12FD00001396000000000000000000000000000000000000002D00000000kube-kompare-0.0.2~alpha3/cli/parser_test.gopackage cli

import (
	"os"
	"reflect"
	"testing"
)

func TestPaserReader(t *testing.T) {
	// Store original os.Args and defer its restoration
	originalArgs := os.Args
	defer func() { os.Args = originalArgs }()

	// Define test command-line arguments
	testArgs := []string{
		"program_name",
		"-t", "target-context",
		"-i", "deployment,service",
		"-v",
	}

	// Set os.Args to testArgs
	os.Args = testArgs

	// Call the function under test
	args := PaserReader()

	// Add assertions to validate the parsed arguments
	// For example, you can check if the target context and included objects are set correctly
	if args.TargetClusterContext != "target-context" {
		t.Errorf("Expected target context 'target-context', got %s", args.TargetClusterContext)
	}

	if args.Include[0] != "deployment" || args.Include[1] != "service" {
		t.Errorf("Expected included objects 'deployment' and 'service', got %v", args.Include)
	}

	if args.VerboseDiffs != 1 {
		t.Errorf("Expected verbose mode enabled, got %d", args.VerboseDiffs)
	}
}

func TestValidateParametersFromParserArgs(t *testing.T) {
	testCases := []struct {
		name                  string
		argsReceived          ArgumentsReceived
		expectedArgsValidated ArgumentsReceivedValidated
	}{
		{
			name: "Valid Arguments",
			argsReceived: ArgumentsReceived{
				KubeconfigFile:       stringPtr("/path/to/kubeconfig"),
				SourceClusterContext: stringPtr("source-context"),
				TargetClusterContext: stringPtr("target-context"),
				NamespaceName:        stringPtr("default"),
				FiltersForObject:     stringPtr("filter"),
				Include:              stringPtr("deployment"),
				Exclude:              stringPtr("service"),
				VerboseDiffs:         intPtr(1),
				FileOutput:           stringPtr("output.txt"),
				Err:                  nil,
			},
			expectedArgsValidated: ArgumentsReceivedValidated{
				KubeconfigFile:       "/path/to/kubeconfig",
				SourceClusterContext: "source-context",
				TargetClusterContext: "target-context",
				NamespaceName:        "default",
				FiltersForObject:     "filter",
				Include:              []string{"deployment"},
				Exclude:              []string{"service"},
				VerboseDiffs:         1,
				FileOutput:           "output.txt",
				Err:                  nil,
			},
		},
		// Add more test cases as needed
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			// Call the function under test
			actualArgsValidated := ValidateParametersFromParserArgs(tc.argsReceived)

			// Compare the actual and expected results
			if !argsValidatedEqual(actualArgsValidated, tc.expectedArgsValidated) {
				t.Errorf("Test case '%s': Expected %v, got %v", tc.name, tc.expectedArgsValidated, actualArgsValidated)
			}
		})
	}
}

// Utility functions for creating pointers

func stringPtr(s string) *string {
	return &s
}

func intPtr(i int) *int {
	return &i
}

// Helper function to check equality of ArgumentsReceivedValidated structs
func argsValidatedEqual(a, b ArgumentsReceivedValidated) bool {
	return a.KubeconfigFile == b.KubeconfigFile &&
		a.SourceClusterContext == b.SourceClusterContext &&
		a.TargetClusterContext == b.TargetClusterContext &&
		a.NamespaceName == b.NamespaceName &&
		a.FiltersForObject == b.FiltersForObject &&
		stringSliceEqual(a.Include, b.Include) &&
		stringSliceEqual(a.Exclude, b.Exclude) &&
		a.VerboseDiffs == b.VerboseDiffs &&
		a.Err == b.Err
}

// Helper function to check equality of string slices
func stringSliceEqual(a, b []string) bool {
	if len(a) != len(b) {
		return false
	}
	for i := range a {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}

func TestValidateKubernetesObjects(t *testing.T) {
	testCases := []struct {
		name            string
		inputObjects    []string
		expectedInvalid []string
		expectedValid   []string
	}{
		{
			name:            "Valid Objects",
			inputObjects:    []string{"deployment", "ing", "sa", "configmaps", "secret", "namespace", "role", "rolebindings", "clusterrolebinding", "crd"},
			expectedInvalid: nil,
			expectedValid:   []string{"deployment", "ingress", "serviceaccount", "configmap", "secret", "namespace", "role", "rolebinding", "clusterrolebinding", "crd"},
		},
		{
			name:            "Mixed Objects",
			inputObjects:    []string{"svc", "invalid", "configmap", "rolebinding", "random"},
			expectedInvalid: []string{"invalid", "random"},
			expectedValid:   []string{"service", "configmap", "rolebinding"},
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			invalidObjects, validObjects := ValidateKubernetesObjects(tc.inputObjects)

			// Check if invalid objects match
			if !reflect.DeepEqual(invalidObjects, tc.expectedInvalid) {
				t.Errorf("Test case '%s': Expected invalid objects %v, got %v", tc.name, tc.expectedInvalid, invalidObjects)
			}

			// Check if valid objects match
			if !reflect.DeepEqual(validObjects, tc.expectedValid) {
				t.Errorf("Test case '%s': Expected valid objects %v, got %v", tc.name, tc.expectedValid, validObjects)
			}
		})
	}
}
07070100000014000041ED00000000000000000000000265DC12FD00000000000000000000000000000000000000000000002200000000kube-kompare-0.0.2~alpha3/compare07070100000015000081A400000000000000000000000165DC12FD000003FB000000000000000000000000000000000000003900000000kube-kompare-0.0.2~alpha3/compare/clusterrolebindings.gopackage compare

import (
	"fmt"
	"kompare/DAO"
	"kompare/cli"
	"kompare/query"
	"kompare/tools"

	"k8s.io/client-go/kubernetes"
)

func CompareClusterRoleBindings(clientsetToSource, clientsetToTarget *kubernetes.Clientset, TheArgs cli.ArgumentsReceivedValidated) ([]DAO.DiffWithName, error) {
	var TheDiff []DAO.DiffWithName
	sourceClusterRoleBindings, err := query.ListClusterRoleBindings(clientsetToSource)
	if err != nil {
		fmt.Printf("Error getting cluster role list: %v\n", err)
		return TheDiff, err
	}
	targetClusterRoleBindings, err := query.ListClusterRoleBindings(clientsetToTarget)
	if err != nil {
		fmt.Printf("Error getting cluster role list: %v\n", err)
		return TheDiff, err
	}
	var diffCriteria []string
	if TheArgs.FiltersForObject == "" {
		diffCriteria = []string{"RoleRef", "Name", "Annotations"}
	} else {
		diffCriteria = tools.ParseCommaSeparateList(TheArgs.FiltersForObject)
	}
	return CompareVerboseVSNonVerbose(sourceClusterRoleBindings, targetClusterRoleBindings, diffCriteria, TheArgs)
}
07070100000016000081A400000000000000000000000165DC12FD000003C8000000000000000000000000000000000000003200000000kube-kompare-0.0.2~alpha3/compare/clusterroles.gopackage compare

import (
	"fmt"
	"kompare/DAO"
	"kompare/cli"
	"kompare/query"
	"kompare/tools"

	"k8s.io/client-go/kubernetes"
)

func CompareClusterRoles(clientsetToSource, clientsetToTarget *kubernetes.Clientset, TheArgs cli.ArgumentsReceivedValidated) ([]DAO.DiffWithName, error) {
	var TheDiff []DAO.DiffWithName
	sourceClusterRoles, err := query.ListClusterRoles(clientsetToSource)
	if err != nil {
		fmt.Printf("Error getting cluster role list: %v\n", err)
		return TheDiff, err
	}
	targetClusterRoles, err := query.ListClusterRoles(clientsetToTarget)
	if err != nil {
		fmt.Printf("Error getting cluster role list: %v\n", err)
		return TheDiff, err
	}
	var diffCriteria []string
	if TheArgs.FiltersForObject == "" {
		diffCriteria = []string{"Rules", "Name", "Annotations"}
	} else {
		diffCriteria = tools.ParseCommaSeparateList(TheArgs.FiltersForObject)
	}
	return CompareVerboseVSNonVerbose(sourceClusterRoles, targetClusterRoles, diffCriteria, TheArgs)
}
07070100000017000081A400000000000000000000000165DC12FD0000517F000000000000000000000000000000000000002D00000000kube-kompare-0.0.2~alpha3/compare/compare.gopackage compare

import (
	"fmt"
	"reflect"
	"strings"

	"github.com/go-test/deep"

	"kompare/DAO"
	"kompare/cli"
	"kompare/tools"

	v1 "k8s.io/api/apps/v1"
	autoscalingv1 "k8s.io/api/autoscaling/v1"
	batchv1 "k8s.io/api/batch/v1"
	Corev1 "k8s.io/api/core/v1"
	networkingv1 "k8s.io/api/networking/v1"
	RbacV1 "k8s.io/api/rbac/v1"
	apiextensionv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
	"k8s.io/client-go/kubernetes"
)

type TypeAssertionFunc func(interface{}) (bool, interface{})

// typeAssertions is a map containing type assertion functions for various Kubernetes resource lists.
// Each entry in the map consists of a string key representing the type of Kubernetes resource list
// and a corresponding TypeAssertionFunc, which is a function type.
var typeAssertions = map[string]TypeAssertionFunc{
	"*Corev1.NamespaceList": func(obj interface{}) (bool, interface{}) {
		val, ok := obj.(*Corev1.NamespaceList)
		return ok, val
	},
	"*v1.DeploymentList": func(obj interface{}) (bool, interface{}) {
		val, ok := obj.(*v1.DeploymentList)
		return ok, val
	},
	"*autoscalingv1.HorizontalPodAutoscalerList": func(obj interface{}) (bool, interface{}) {
		val, ok := obj.(*autoscalingv1.HorizontalPodAutoscalerList)
		return ok, val
	},
	"*batchv1.CronJobList": func(obj interface{}) (bool, interface{}) {
		val, ok := obj.(*batchv1.CronJobList)
		return ok, val
	},
	"*apiextensionv1.CustomResourceDefinitionList": func(obj interface{}) (bool, interface{}) {
		val, ok := obj.(*apiextensionv1.CustomResourceDefinitionList)
		return ok, val
	},
	"*networkingv1.IngressList": func(obj interface{}) (bool, interface{}) {
		val, ok := obj.(*networkingv1.IngressList)
		return ok, val
	},
	"*Corev1.ServiceList": func(obj interface{}) (bool, interface{}) {
		val, ok := obj.(*Corev1.ServiceList)
		return ok, val
	},
	"*Corev1.ConfigMapList": func(obj interface{}) (bool, interface{}) {
		val, ok := obj.(*Corev1.ConfigMapList)
		return ok, val
	},
	"*Corev1.SecretList": func(obj interface{}) (bool, interface{}) {
		val, ok := obj.(*Corev1.SecretList)
		return ok, val
	},
	"*Corev1.ServiceAccountList": func(obj interface{}) (bool, interface{}) {
		val, ok := obj.(*Corev1.ServiceAccountList)
		return ok, val
	},
	"*RbacV1.RoleList": func(obj interface{}) (bool, interface{}) {
		val, ok := obj.(*RbacV1.RoleList)
		return ok, val
	},
	"*RbacV1.RoleBindingList": func(obj interface{}) (bool, interface{}) {
		val, ok := obj.(*RbacV1.RoleBindingList)
		return ok, val
	},
	"*RbacV1.ClusterRoleList": func(obj interface{}) (bool, interface{}) {
		val, ok := obj.(*RbacV1.ClusterRoleList)
		return ok, val
	},
	"*RbacV1.ClusterRoleBindingList": func(obj interface{}) (bool, interface{}) {
		val, ok := obj.(*RbacV1.ClusterRoleBindingList)
		return ok, val
	},
	"*networkingv1.NetworkPolicyList": func(obj interface{}) (bool, interface{}) {
		val, ok := obj.(*networkingv1.NetworkPolicyList)
		return ok, val
	},
}

func GetTypeInfo(obj interface{}) (string, interface{}) {
	typeName := "unknown"
	var objValue interface{}

	for t, assertionFunc := range typeAssertions {
		if success, value := assertionFunc(obj); success {
			typeName = t
			objValue = value
			break
		}
	}

	return typeName, objValue
}

// GenericCountListElements counts the number of elements in a generic list object.
// It checks the type of the object and extracts its value.
// If the object has an "Items" field and it's of slice type, it returns the length of the slice.
// If the object does not meet the criteria for counting elements, it returns 0.
func GenericCountListElements(obj interface{}) int {
	// Check the type of the object
	_, objValue := GetTypeInfo(obj)

	// Check if it's a list type with an "Items" field
	if hasItemsField(objValue) {
		// Get the "Items" field of the list
		itemsField := reflect.ValueOf(objValue).Elem().FieldByName("Items")

		// Check if the field is a slice
		if itemsField.Kind() == reflect.Slice {
			// Return the length of the slice
			return itemsField.Len()
		}
	}

	return 0
}

// hasItemsField checks if an object has an "Items" field.
// It takes an interface{} as input and inspects its type and value using reflection.
// If the object is a pointer to a struct and the struct has a field named "Items",
// it returns true if the "Items" field exists in the value, otherwise returns false.
func hasItemsField(obj interface{}) bool {
	objType := reflect.TypeOf(obj)
	objValue := reflect.ValueOf(obj)

	// Check if it's a struct
	if objType.Kind() == reflect.Ptr && objType.Elem().Kind() == reflect.Struct {
		// Dereference the pointer to get the struct type
		structType := objType.Elem()

		// Check if the struct has a field named "Items"
		if _, found := structType.FieldByName("Items"); found {
			// Check if the "Items" field exists in the value
			return objValue.Elem().FieldByName("Items").IsValid()
		}
	}

	return false
}

// CompareNumbersGenericOutput prints a comparison result between two numbers along with a description of what they represent.
// It takes two integers (number1 and number2) representing counts from different clusters and an interface{} (what) as input.
// The interface{} parameter is expected to describe the type of objects being compared.
// It formats and prints a comparison message indicating the count of objects represented by 'what'
// in the source cluster (number1) compared to the count in the target cluster (number2).
func CompareNumbersGenericOutput(number1, number2 int, what interface{}) {
	fmt.Printf("The number of %s in the source cluster is %d and there are %d in the target cluster.\n",
		tools.ConvertTypeStringToHumanReadable(what), number1, number2)
}

// IterateGenericSimpleDiff iterates over two generic interfaces representing lists of objects
// and identifies the differences between them.
// It takes sourceInterface and targetInterface as input, which are interfaces representing lists of objects.
// It calculates the lengths of both interfaces and compares them.
// If the lengths are not equal, it prints a notice indicating the discrepancy.
// It currently returns empty slices for differences since the comparison logic is not implemented.
// Further implementation is required to compare the actual objects and identify differences.
// The function returns two empty string slices for differences.
func IterateGenericSimpleDiff(sourceInterface, targetInterface interface{}) ([]string, []string) {
	lenSourceInterface := GenericCountListElements(sourceInterface)
	lenTargetInterface := GenericCountListElements(targetInterface)
	if lenSourceInterface != lenTargetInterface {
		// var onlyInSource, onlyInTarget []string

		fmt.Printf("NOTICE: not equal number of %v!!!\n", tools.ConvertTypeStringToHumanReadable(sourceInterface))
		// need to compare interfaces by finding each items name like in the static IterateDeploymentsSimpleDiff function
	}

	return nil, nil
}

// CompareByName compares objects in two interfaces by their names.
// It takes two interface{} parameters (firstInterface and secondInterface) representing lists of objects,
// and a string message_heading as input.
// It extracts the "Items" field from both interfaces and iterates through the items in the first interface.
// For each item in the first interface, it checks if the item is present in the second interface.
// If an item is not present in the second interface, it generates and prints a message using the message_heading
// and appends the item's name to the diffNameList.
// The function returns a slice containing the names of the items that are present in the first interface
// but not in the second interface.
func CompareByName(firstInterface, secondInterface interface{}, message_heading string) []string {
	var diffNameList []string

	// Extract the "Items" field from the first and second interfaces
	firstItems := reflect.ValueOf(firstInterface).Elem().FieldByName("Items")
	secondItems := reflect.ValueOf(secondInterface).Elem().FieldByName("Items")

	// Check if both fields are slices
	if firstItems.Kind() == reflect.Slice && secondItems.Kind() == reflect.Slice {
		// Loop through the items in the first interface
		for i := 0; i < firstItems.Len(); i++ {
			item := firstItems.Index(i).Interface()

			// Check if the item is not present in the second interface
			if !containsItem(item, secondItems) {
				fmt.Println(generateMessage(message_heading, tools.ConvertTypeStringToHumanReadable(item), getName(item)))
				diffNameList = append(diffNameList, getName(item))
			}
		}
	}
	return diffNameList
}

// generateMessage generates a generic message using a template, object type, and item name.
// It takes three string parameters: template, objectType, and ItemName.
// It formats and returns a message by inserting the objectType and ItemName into the template.
func generateMessage(template, objectType, ItemName string) string {
	return fmt.Sprintf(template, objectType, ItemName)
}

// containsItem checks if an item is present in the second interface.
// It takes an item interface{} and a reflect.Value (secondItems) representing the second interface.
// It loops through the items in the second interface and compares each item's name with the name of the provided item.
// If a matching item is found, it returns true; otherwise, it returns false.
func containsItem(item interface{}, secondItems reflect.Value) bool {
	// Loop through the items in the second interface
	for i := 0; i < secondItems.Len(); i++ {
		secondItem := secondItems.Index(i).Interface()

		// Compare items by name
		if getName(item) == getName(secondItem) {
			return true
		}
	}

	return false
}

// getName retrieves the name of an item assuming it has a "Name" field.
// It takes an item interface{} as input and extracts the value of the "Name" field.
// If the field is valid and of type string, it returns the string value of the field.
// If the field is invalid or not of type string, it returns an empty string.
func getName(item interface{}) string {
	nameField := reflect.ValueOf(item).FieldByName("Name")
	if nameField.IsValid() && nameField.Kind() == reflect.String {
		return nameField.String()
	}
	return ""
}

// getNestedFieldValue retrieves the value of a nested field within a structure using reflection.
// It takes a reflect.Value (obj) representing the structure and a slice of strings (fieldNames) representing the nested field names.
// It iterates through each field name in the fieldNames slice and accesses the corresponding nested field in the structure.
// If the structure contains pointers, it dereferences them to access the nested fields.
// If a nested field is not found or is invalid, it returns an error indicating the missing field.
// Otherwise, it returns the reflect.Value of the nested field.
func getNestedFieldValue(obj reflect.Value, fieldNames []string) (reflect.Value, error) {
	for _, fieldName := range fieldNames {
		// Dereference pointers in the nested structure
		if obj.Kind() == reflect.Ptr {
			obj = obj.Elem()
		}

		// Access the nested field
		obj = obj.FieldByName(fieldName)

		// Check if the field is valid
		if !obj.IsValid() {
			return reflect.Value{}, fmt.Errorf("Field %s not found", fieldName)
		}
	}

	return obj, nil
}

// DeepCompare performs a deep comparison between two interfaces representing lists of objects.
// It compares the objects based on specified criteria and returns a list of differences along with their names and namespaces.
// It takes sourceInterface and targetInterface as input interfaces and DiffCriteria as a slice of strings representing comparison criteria.
// It iterates over the 'Items' fields of both sourceInterface and targetInterface and compares each item's 'Name' field.
// If the 'Name' fields match, it compares the specified DiffCriteria fields of the objects using the deep.Equal function from the 'github.com/go-test/deep' package.
// It constructs DiffWithName structs containing the object name, namespace, difference details, and property name for each difference found.
// The function returns a slice of DiffWithName containing the differences between the source and target interfaces based on the specified criteria.
func DeepCompare(sourceInterface, targetInterface interface{}, DiffCriteria []string) ([]DAO.DiffWithName, error) {
	var tmpDiff DAO.DiffWithName
	var diffSourceTarget []DAO.DiffWithName
	// Get type information for source and target
	_, sourceObject := GetTypeInfo(sourceInterface)
	_, targetObject := GetTypeInfo(targetInterface)
	sourceItemsField := reflect.ValueOf(sourceObject).Elem().FieldByName("Items")
	targetItemsField := reflect.ValueOf(targetObject).Elem().FieldByName("Items")
	// Check if 'Items' is a slice in both source and target objects
	if sourceItemsField.Kind() == reflect.Slice && targetItemsField.Kind() == reflect.Slice {
		// Iterate over sourceItems
		for i := 0; i < sourceItemsField.Len(); i++ {
			sourceItem := sourceItemsField.Index(i).Interface()

			// Iterate over targetItems
			for j := 0; j < targetItemsField.Len(); j++ {
				targetItem := targetItemsField.Index(j).Interface()
				// Compare 'Name' fields
				sourceName, _ := getNestedFieldValue(reflect.ValueOf(sourceItem), []string{"Name"})
				targetName, _ := getNestedFieldValue(reflect.ValueOf(targetItem), []string{"Name"})
				sourceNamespace, _ := getNestedFieldValue(reflect.ValueOf(sourceItem), []string{"Namespace"})
				if sourceName.String() == targetName.String() {
					for _, v := range DiffCriteria {
						sourceDiffCriteriaField, err := getNestedFieldValue(reflect.ValueOf(sourceItem), strings.Split(v, "."))
						if err != nil {
							fmt.Printf("Error accessing field: %v\n", err)
							continue
						}
						targetDiffCriteriaField, err := getNestedFieldValue(reflect.ValueOf(targetItem), strings.Split(v, "."))
						if err != nil {
							fmt.Printf("Error accessing field: %v\n", err)
							continue
						}
						xdiff := deep.Equal(sourceDiffCriteriaField.Interface(), targetDiffCriteriaField.Interface())
						tmpDiff.Name = targetName.String()
						tmpDiff.Namespace = sourceNamespace.String()
						tmpDiff.Diff = xdiff
						tmpDiff.PropertyName = v
						diffSourceTarget = append(diffSourceTarget, tmpDiff)
					}
				}
			}
		}
	} else {
		fmt.Println("'Items' field is not a slice in source or target object.")
	}

	return diffSourceTarget, nil
}

// ShowResourceComparison compares two sets of resources from different clusters and identifies differences based on specified criteria.
// It takes sourceResource and targetResource as input interfaces representing lists of resources from different clusters,
// and diffCriteria as a slice of strings representing comparison criteria.
// It calculates the lengths of sourceResource and targetResource and compares them.
// If the lengths are different, it prints a message indicating the discrepancy and performs a number comparison.
// It then compares the resources in both clusters using the CompareByName function and prints the differences.
// It also performs a deep comparison of resources based on the specified diffCriteria using the DeepCompare function.
// The function returns a slice of DiffWithName containing the differences between the source and target resources,
// along with any error encountered during the comparison.
func ShowResourceComparison(sourceResource, targetResource interface{}, diffCriteria []string, args cli.ArgumentsReceivedValidated) ([]DAO.DiffWithName, error) {
	var TheDiff []DAO.DiffWithName
	lensourceResource := GenericCountListElements(sourceResource)
	lentargetResource := GenericCountListElements(targetResource)
	resourceType := tools.ConvertTypeStringToHumanReadable(sourceResource)

	messageheading := "* These two cluster do not have the same number of " + resourceType + ", please check it manually! *"
	lenMessageheading := len(messageheading)
	if args.VerboseDiffs != 0 {
		if lentargetResource != lensourceResource {

			fmt.Println(strings.Repeat("*", lenMessageheading))
			fmt.Println(messageheading)
			fmt.Println(strings.Repeat("*", lenMessageheading))
			CompareNumbersGenericOutput(lensourceResource, lentargetResource, targetResource)
		}
		fmt.Println(strings.Repeat("*", lenMessageheading))
		sourceMessageTemplate := "- First cluster has %s: %s, but it's not in the second cluster\n"
		resultStringsSvT := CompareByName(sourceResource, targetResource, sourceMessageTemplate)
		if len(resultStringsSvT) > 0 {
			fmt.Println(strings.Repeat("*", lenMessageheading))
		} else {
			fmt.Println("Done compering source cluster versus target cluster's ", resourceType)
		}
		targetmessageTemplate := "- Second cluster has %s: %s, but it's not in the first cluster\n"
		resultStringsTvS := CompareByName(targetResource, sourceResource, targetmessageTemplate)
		if len(resultStringsTvS) > 0 {
			fmt.Println(strings.Repeat("*", lenMessageheading))
		} else {
			fmt.Println("Done compering target cluster versus source cluster's ", resourceType)
		}
		TheDiff, _ = DeepCompare(targetResource, sourceResource, diffCriteria)
		return TheDiff, nil
	}
	if lentargetResource != lensourceResource {
		fmt.Println(strings.Repeat("*", lenMessageheading))
		fmt.Println(messageheading)
		fmt.Println(strings.Repeat("*", lenMessageheading))
		CompareNumbersGenericOutput(lensourceResource, lentargetResource, targetResource)
	}
	TheDiff, _ = DeepCompare(targetResource, sourceResource, diffCriteria)
	return TheDiff, nil
}

// CompareVerboseVSNonVerbose compares two sets of namespaces from different clusters based on specified criteria.
// It takes sourceNameSpacesList and targetNameSpacesList as input interfaces representing lists of namespaces from different clusters,
// diffCriteria as a slice of strings representing comparison criteria, and boolverboseDiffs as a pointer to a boolean indicating whether to display verbose differences.
// If args is the aguments passed like for instance VerboseDiffs for the level of verbosity desired.
// The function returns a slice of DiffWithName containing the differences between the source and target namespaces,
// along with any error encountered during the comparison.
func CompareVerboseVSNonVerbose(sourceNameSpacesList, targetNameSpacesList interface{}, diffCriteria []string, args cli.ArgumentsReceivedValidated) ([]DAO.DiffWithName, error) {
	if args.VerboseDiffs != 0 {
		if args.VerboseDiffs > 1 {
			TheDiff, err := ShowResourceComparison(sourceNameSpacesList, targetNameSpacesList, diffCriteria, args)
			fmt.Println(tools.FormatDiffHumanReadable(TheDiff))
			return TheDiff, err
		} else if args.VerboseDiffs == 1 {
			return ShowResourceComparison(sourceNameSpacesList, targetNameSpacesList, diffCriteria, args)
		}

	}
	// sumary goes here.
	return ShowResourceComparison(sourceNameSpacesList, targetNameSpacesList, diffCriteria, args)
}

// GenericCompareResources compares resources between two Kubernetes clusters based on specified criteria.
// It takes clientsetToSource and clientsetToTarget as pointers to kubernetes.Clientset representing connections to the source and target clusters,
// namespaceName as a string specifying the namespace to compare resources in,
// resourceGetter as a function to retrieve the list of resources from a clientset and namespace,
// diffCriteria as a slice of strings representing comparison criteria,
// and boolverboseDiffs as a pointer to a boolean indicating whether to display verbose differences.
// It retrieves the list of resources from both the source and target clusters using the resourceGetter function.
// It then performs a comparison between the resources from both clusters using the CompareVerboseVSNonVerbose function.
// The function returns a slice of DiffWithName containing the differences between the source and target resources,
// along with any error encountered during the comparison.
func GenericCompareResources(clientsetToSource, clientsetToTarget *kubernetes.Clientset, namespaceName string, resourceGetter func(*kubernetes.Clientset, string) (interface{}, error), diffCriteria []string, args cli.ArgumentsReceivedValidated) ([]DAO.DiffWithName, error) {
	var TheDiff []DAO.DiffWithName

	sourceResources, err := resourceGetter(clientsetToSource, namespaceName)
	if err != nil {
		return TheDiff, fmt.Errorf("error getting source resources: %v", err)
	}

	targetResources, err := resourceGetter(clientsetToTarget, namespaceName)
	if err != nil {
		return TheDiff, fmt.Errorf("error getting target resources: %v", err)
	}

	// Type assertion to convert the interface{} to a slice of the specific type
	sourceSlice, ok := sourceResources.([]interface{})
	if !ok {
		return TheDiff, fmt.Errorf("unexpected type for source resources")
	}

	targetSlice, ok := targetResources.([]interface{})
	if !ok {
		return TheDiff, fmt.Errorf("unexpected type for target resources")
	}

	return CompareVerboseVSNonVerbose(sourceSlice, targetSlice, diffCriteria, args)
}
07070100000018000081A400000000000000000000000165DC12FD000003EC000000000000000000000000000000000000003000000000kube-kompare-0.0.2~alpha3/compare/configmaps.gopackage compare

import (
	"fmt"
	"kompare/DAO"
	"kompare/cli"
	"kompare/query"
	"kompare/tools"

	"k8s.io/client-go/kubernetes"
)

func CompareConfigMaps(clientsetToSource, clientsetToTarget *kubernetes.Clientset, namespaceName string, TheArgs cli.ArgumentsReceivedValidated) ([]DAO.DiffWithName, error) {

	var TheDiff []DAO.DiffWithName
	sourceConfigMaps, err := query.ListConfigMaps(clientsetToSource, namespaceName)
	if err != nil {
		fmt.Printf("Error getting deployments list: %v\n", err)
		return TheDiff, err
	}
	targetConfigMaps, err := query.ListConfigMaps(clientsetToTarget, namespaceName)
	if err != nil {
		fmt.Printf("Error getting deployments list: %v\n", err)
		return TheDiff, err
	}
	var diffCriteria []string
	if TheArgs.FiltersForObject == "" {
		diffCriteria = []string{"Data", "Name", "Annotations"}
	} else {
		diffCriteria = tools.ParseCommaSeparateList(TheArgs.FiltersForObject)
	}
	return CompareVerboseVSNonVerbose(sourceConfigMaps, targetConfigMaps, diffCriteria, TheArgs)
}
07070100000019000081A400000000000000000000000165DC12FD00000379000000000000000000000000000000000000002A00000000kube-kompare-0.0.2~alpha3/compare/crds.gopackage compare

import (
	"fmt"
	"kompare/DAO"
	"kompare/cli"
	"kompare/query"
	"kompare/tools"
)

// Compare CRDs using generic functions from module "compare"
func CompareCRDs(targetContext, configFile string, TheArgs cli.ArgumentsReceivedValidated) ([]DAO.DiffWithName, error) {
	var TheDiff []DAO.DiffWithName
	sourceCRDs, err := query.ListCRDs("", configFile)
	if err != nil {
		fmt.Printf("Error getting CRDs list: %v\n", err)
		return TheDiff, err
	}
	targetCRDs, err := query.ListCRDs(targetContext, configFile)
	if err != nil {
		fmt.Printf("Error getting CRDs list: %v\n", err)
		return TheDiff, err
	}
	var diffCriteria []string
	if TheArgs.FiltersForObject == "" {
		diffCriteria = []string{"Spec", "Name"}
	} else {
		diffCriteria = tools.ParseCommaSeparateList(TheArgs.FiltersForObject)
	}
	return CompareVerboseVSNonVerbose(sourceCRDs, targetCRDs, diffCriteria, TheArgs)
}
0707010000001A000081A400000000000000000000000165DC12FD000003C8000000000000000000000000000000000000002E00000000kube-kompare-0.0.2~alpha3/compare/cronjobs.gopackage compare

import (
	"fmt"
	"kompare/DAO"
	"kompare/cli"
	"kompare/query"
	"kompare/tools"

	"k8s.io/client-go/kubernetes"
)

func CompareCronJobs(clientsetToSource, clientsetToTarget *kubernetes.Clientset, namespaceName string, TheArgs cli.ArgumentsReceivedValidated) ([]DAO.DiffWithName, error) {
	var TheDiff []DAO.DiffWithName
	sourceCronJobs, err := query.ListCronJobs(clientsetToSource, namespaceName)
	if err != nil {
		fmt.Printf("Error getting services list: %v\n", err)
		return TheDiff, err
	}
	targetCronJobs, err := query.ListCronJobs(clientsetToSource, namespaceName)
	if err != nil {
		fmt.Printf("Error getting services list: %v\n", err)
		return TheDiff, err
	}
	var diffCriteria []string
	if TheArgs.FiltersForObject == "" {
		diffCriteria = []string{"Spec", "Name"}
	} else {
		diffCriteria = tools.ParseCommaSeparateList(TheArgs.FiltersForObject)
	}
	return CompareVerboseVSNonVerbose(sourceCronJobs, targetCronJobs, diffCriteria, TheArgs)
}
0707010000001B000081A400000000000000000000000165DC12FD00000418000000000000000000000000000000000000003100000000kube-kompare-0.0.2~alpha3/compare/deployments.gopackage compare

import (
	"fmt"
	"kompare/DAO"
	"kompare/cli"
	"kompare/query"
	"kompare/tools"

	"k8s.io/client-go/kubernetes"
)

// compare deployments for a namespace
func CompareDeployments(clientsetToSource, clientsetToTarget *kubernetes.Clientset, namespaceName string, TheArgs cli.ArgumentsReceivedValidated) ([]DAO.DiffWithName, error) {
	var TheDiff []DAO.DiffWithName
	sourceDeployments, err := query.ListDeployments(clientsetToSource, namespaceName)
	if err != nil {
		fmt.Printf("Error getting deployments list: %v\n", err)
		return TheDiff, err
	}
	targetDeplotments, err := query.ListDeployments(clientsetToTarget, namespaceName)
	if err != nil {
		fmt.Printf("Error getting deployments list: %v\n", err)
		return TheDiff, err
	}
	var diffCriteria []string
	if TheArgs.FiltersForObject == "" {
		diffCriteria = []string{"Spec.Template.Spec", "Name"}
	} else {
		diffCriteria = tools.ParseCommaSeparateList(TheArgs.FiltersForObject)
	}
	return CompareVerboseVSNonVerbose(sourceDeployments, targetDeplotments, diffCriteria, TheArgs)
}
0707010000001C000081A400000000000000000000000165DC12FD000003AC000000000000000000000000000000000000002900000000kube-kompare-0.0.2~alpha3/compare/hpa.gopackage compare

import (
	"fmt"
	"kompare/DAO"
	"kompare/cli"
	"kompare/query"
	"kompare/tools"

	"k8s.io/client-go/kubernetes"
)

func CompareHPAs(clientsetToSource, clientsetToTarget *kubernetes.Clientset, namespaceName string, TheArgs cli.ArgumentsReceivedValidated) ([]DAO.DiffWithName, error) {
	var TheDiff []DAO.DiffWithName
	sourceHPAs, err := query.ListHPAs(clientsetToSource, namespaceName)
	if err != nil {
		fmt.Printf("Error getting services list: %v\n", err)
		return TheDiff, err
	}
	targetHPAs, err := query.ListHPAs(clientsetToSource, namespaceName)
	if err != nil {
		fmt.Printf("Error getting services list: %v\n", err)
		return TheDiff, err
	}
	var diffCriteria []string
	if TheArgs.FiltersForObject == "" {
		diffCriteria = []string{"Spec", "Name"}
	} else {
		diffCriteria = tools.ParseCommaSeparateList(TheArgs.FiltersForObject)
	}
	return CompareVerboseVSNonVerbose(sourceHPAs, targetHPAs, diffCriteria, TheArgs)
}
0707010000001D000081A400000000000000000000000165DC12FD000003DE000000000000000000000000000000000000002F00000000kube-kompare-0.0.2~alpha3/compare/ingresses.gopackage compare

import (
	"fmt"
	"kompare/DAO"
	"kompare/cli"
	"kompare/query"
	"kompare/tools"

	"k8s.io/client-go/kubernetes"
)

func CompareIngresses(clientsetToSource, clientsetToTarget *kubernetes.Clientset, namespaceName string, TheArgs cli.ArgumentsReceivedValidated) ([]DAO.DiffWithName, error) {
	var TheDiff []DAO.DiffWithName
	sourceIngresses, err := query.ListIngresses(clientsetToSource, namespaceName)
	if err != nil {
		fmt.Printf("Error getting services list: %v\n", err)
		return TheDiff, err
	}
	targetIngresses, err := query.ListIngresses(clientsetToSource, namespaceName)
	if err != nil {
		fmt.Printf("Error getting services list: %v\n", err)
		return TheDiff, err
	}
	var diffCriteria []string
	if TheArgs.FiltersForObject == "" {
		diffCriteria = []string{"Spec", "Name", "Annotations"}
	} else {
		diffCriteria = tools.ParseCommaSeparateList(TheArgs.FiltersForObject)
	}
	return CompareVerboseVSNonVerbose(sourceIngresses, targetIngresses, diffCriteria, TheArgs)
}
0707010000001E000081A400000000000000000000000165DC12FD0000041A000000000000000000000000000000000000003000000000kube-kompare-0.0.2~alpha3/compare/namespaces.gopackage compare

import (
	"fmt"
	"kompare/DAO"
	"kompare/cli"
	"kompare/query"
	"kompare/tools"

	"k8s.io/client-go/kubernetes"
)

// Compare actual namespaces comparison using generic functions from module "compare"
func CompareNameSpaces(clientsetToSource, clientsetToTarget *kubernetes.Clientset, TheArgs cli.ArgumentsReceivedValidated) ([]DAO.DiffWithName, error) {
	var TheDiff []DAO.DiffWithName
	sourceNameSpacesList, err := query.ListNameSpaces(clientsetToSource)
	if err != nil {
		fmt.Printf("Error getting namespace list: %v\n", err)
		return TheDiff, err
	}
	targetNameSpacesList, err := query.ListNameSpaces(clientsetToTarget)
	if err != nil {
		fmt.Printf("Error getting namespace list: %v\n", err)
		return TheDiff, err
	}
	var diffCriteria []string
	if TheArgs.FiltersForObject == "" {
		diffCriteria = []string{"Spec", "Name", "Status.Phase"}
	} else {
		diffCriteria = tools.ParseCommaSeparateList(TheArgs.FiltersForObject)
	}
	return CompareVerboseVSNonVerbose(sourceNameSpacesList, targetNameSpacesList, diffCriteria, TheArgs)
}
0707010000001F000081A400000000000000000000000165DC12FD00000408000000000000000000000000000000000000003300000000kube-kompare-0.0.2~alpha3/compare/networkpolicy.gopackage compare

import (
	"fmt"
	"kompare/DAO"
	"kompare/cli"
	"kompare/query"
	"kompare/tools"

	"k8s.io/client-go/kubernetes"
)

func CompareNetworkPolicies(clientsetToSource, clientsetToTarget *kubernetes.Clientset, namespaceName string, TheArgs cli.ArgumentsReceivedValidated) ([]DAO.DiffWithName, error) {
	var TheDiff []DAO.DiffWithName
	sourceNetworkPolicies, err := query.ListNetworkPolicies(clientsetToSource, namespaceName)
	if err != nil {
		fmt.Printf("Error getting services list: %v\n", err)
		return TheDiff, err
	}
	targetNetworkPolicies, err := query.ListNetworkPolicies(clientsetToTarget, namespaceName)
	if err != nil {
		fmt.Printf("Error getting services list: %v\n", err)
		return TheDiff, err
	}
	var diffCriteria []string
	if TheArgs.FiltersForObject == "" {
		diffCriteria = []string{"Spec", "Name", "Annotations"}
	} else {
		diffCriteria = tools.ParseCommaSeparateList(TheArgs.FiltersForObject)
	}
	return CompareVerboseVSNonVerbose(sourceNetworkPolicies, targetNetworkPolicies, diffCriteria, TheArgs)
}
07070100000020000081A400000000000000000000000165DC12FD000003F6000000000000000000000000000000000000003200000000kube-kompare-0.0.2~alpha3/compare/rolebindings.gopackage compare

import (
	"fmt"
	"kompare/DAO"
	"kompare/cli"
	"kompare/query"
	"kompare/tools"

	"k8s.io/client-go/kubernetes"
)

func CompareRoleBindings(clientsetToSource, clientsetToTarget *kubernetes.Clientset, namespaceName string, TheArgs cli.ArgumentsReceivedValidated) ([]DAO.DiffWithName, error) {

	var TheDiff []DAO.DiffWithName
	sourceRoleBindings, err := query.ListRoleBindings(clientsetToSource, namespaceName)
	if err != nil {
		fmt.Printf("Error getting role bindings list: %v\n", err)
		return TheDiff, err
	}
	targetRoleBindings, err := query.ListRoleBindings(clientsetToTarget, namespaceName)
	if err != nil {
		fmt.Printf("Error getting role bindings list: %v\n", err)
		return TheDiff, err
	}
	var diffCriteria []string
	if TheArgs.FiltersForObject == "" {
		diffCriteria = []string{"RoleRef", "Subjects"}
	} else {
		diffCriteria = tools.ParseCommaSeparateList(TheArgs.FiltersForObject)
	}
	return CompareVerboseVSNonVerbose(sourceRoleBindings, targetRoleBindings, diffCriteria, TheArgs)
}
07070100000021000081A400000000000000000000000165DC12FD000003AF000000000000000000000000000000000000002B00000000kube-kompare-0.0.2~alpha3/compare/roles.gopackage compare

import (
	"fmt"
	"kompare/DAO"
	"kompare/cli"
	"kompare/query"
	"kompare/tools"

	"k8s.io/client-go/kubernetes"
)

func CompareRoles(clientsetToSource, clientsetToTarget *kubernetes.Clientset, namespaceName string, TheArgs cli.ArgumentsReceivedValidated) ([]DAO.DiffWithName, error) {

	var TheDiff []DAO.DiffWithName
	sourceRoles, err := query.ListRoles(clientsetToSource, namespaceName)
	if err != nil {
		fmt.Printf("Error getting roles list: %v\n", err)
		return TheDiff, err
	}
	targetRoles, err := query.ListRoles(clientsetToTarget, namespaceName)
	if err != nil {
		fmt.Printf("Error getting roles list: %v\n", err)
		return TheDiff, err
	}
	var diffCriteria []string
	if TheArgs.FiltersForObject == "" {
		diffCriteria = []string{"Rules", "Name"}
	} else {
		diffCriteria = tools.ParseCommaSeparateList(TheArgs.FiltersForObject)
	}
	return CompareVerboseVSNonVerbose(sourceRoles, targetRoles, diffCriteria, TheArgs)
}
07070100000022000081A400000000000000000000000165DC12FD000003C8000000000000000000000000000000000000002D00000000kube-kompare-0.0.2~alpha3/compare/secrets.gopackage compare

import (
	"fmt"
	"kompare/DAO"
	"kompare/cli"
	"kompare/query"
	"kompare/tools"

	"k8s.io/client-go/kubernetes"
)

func CompareSecrets(clientsetToSource, clientsetToTarget *kubernetes.Clientset, namespaceName string, TheArgs cli.ArgumentsReceivedValidated) ([]DAO.DiffWithName, error) {
	var TheDiff []DAO.DiffWithName
	sourceSecrets, err := query.ListServices(clientsetToSource, namespaceName)
	if err != nil {
		fmt.Printf("Error getting secrets list: %v\n", err)
		return TheDiff, err
	}
	targetSecrets, err := query.ListServices(clientsetToSource, namespaceName)
	if err != nil {
		fmt.Printf("Error getting secrets list: %v\n", err)
		return TheDiff, err
	}
	var diffCriteria []string
	if TheArgs.FiltersForObject == "" {
		diffCriteria = []string{"Annotations", "Name"}
	} else {
		diffCriteria = tools.ParseCommaSeparateList(TheArgs.FiltersForObject)
	}
	return CompareVerboseVSNonVerbose(sourceSecrets, targetSecrets, diffCriteria, TheArgs)
}
07070100000023000081A400000000000000000000000165DC12FD00000402000000000000000000000000000000000000003500000000kube-kompare-0.0.2~alpha3/compare/serviceaccounts.gopackage compare

import (
	"fmt"
	"kompare/DAO"
	"kompare/cli"
	"kompare/query"
	"kompare/tools"

	"k8s.io/client-go/kubernetes"
)

func CompareServiceAccounts(clientsetToSource, clientsetToTarget *kubernetes.Clientset, namespaceName string, TheArgs cli.ArgumentsReceivedValidated) ([]DAO.DiffWithName, error) {
	var TheDiff []DAO.DiffWithName
	sourceServiceAccounts, err := query.ListServices(clientsetToSource, namespaceName)
	if err != nil {
		fmt.Printf("Error getting service accounts list: %v\n", err)
		return TheDiff, err
	}
	targetServiceAccounts, err := query.ListServices(clientsetToSource, namespaceName)
	if err != nil {
		fmt.Printf("Error getting service accounts list: %v\n", err)
		return TheDiff, err
	}
	var diffCriteria []string
	if TheArgs.FiltersForObject == "" {
		diffCriteria = []string{"Annotations", "Name"}
	} else {
		diffCriteria = tools.ParseCommaSeparateList(TheArgs.FiltersForObject)
	}
	return CompareVerboseVSNonVerbose(sourceServiceAccounts, targetServiceAccounts, diffCriteria, TheArgs)
}
07070100000024000081A400000000000000000000000165DC12FD000003C8000000000000000000000000000000000000002E00000000kube-kompare-0.0.2~alpha3/compare/services.gopackage compare

import (
	"fmt"
	"kompare/DAO"
	"kompare/cli"
	"kompare/query"
	"kompare/tools"

	"k8s.io/client-go/kubernetes"
)

func CompareServices(clientsetToSource, clientsetToTarget *kubernetes.Clientset, namespaceName string, TheArgs cli.ArgumentsReceivedValidated) ([]DAO.DiffWithName, error) {
	var TheDiff []DAO.DiffWithName
	sourceServices, err := query.ListServices(clientsetToSource, namespaceName)
	if err != nil {
		fmt.Printf("Error getting services list: %v\n", err)
		return TheDiff, err
	}
	targetServices, err := query.ListServices(clientsetToSource, namespaceName)
	if err != nil {
		fmt.Printf("Error getting services list: %v\n", err)
		return TheDiff, err
	}
	var diffCriteria []string
	if TheArgs.FiltersForObject == "" {
		diffCriteria = []string{"Spec", "Name"}
	} else {
		diffCriteria = tools.ParseCommaSeparateList(TheArgs.FiltersForObject)
	}
	return CompareVerboseVSNonVerbose(sourceServices, targetServices, diffCriteria, TheArgs)
}
07070100000025000041ED00000000000000000000000265DC12FD00000000000000000000000000000000000000000000002200000000kube-kompare-0.0.2~alpha3/connect07070100000026000081A400000000000000000000000165DC12FD00001119000000000000000000000000000000000000002D00000000kube-kompare-0.0.2~alpha3/connect/connect.gopackage connect

import (
	"fmt"

	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
)

// CreateConfig creates a Kubernetes configuration based on the provided config file path.
// Parameters:
// - a_config: Pointer to a string containing the path to the Kubernetes config file.
// Returns:
// - (*rest.Config): The built Kubernetes config.
// - (error): An error if any occurred during the config building process.
func CreateConfig(a_config *string) (*rest.Config, error) {
	config_built, err := clientcmd.BuildConfigFromFlags("", *a_config)
	if err != nil {
		return nil, fmt.Errorf("Failed to get the *rest.Config: %w", err)
	}
	return config_built, nil
}

// NewK8sConnectionConfig creates a Kubernetes clientset using the provided config.
// Parameters:
// - a_config_built: Pointer to a rest.Config containing the Kubernetes config.
// Returns:
// - (*kubernetes.Clientset): The created Kubernetes clientset.
// - (error): An error if any occurred during the clientset creation process.
func NewK8sConnectionConfig(a_config_built *rest.Config) (*kubernetes.Clientset, error) {
	the_clientset, err := kubernetes.NewForConfig(a_config_built)
	if err != nil {
		return nil, fmt.Errorf("Failed to get the *kubernetes.Clientset: %w", err)
	}
	return the_clientset, nil
}

// ConnectNow creates a Kubernetes clientset using the provided config file path.
// Parameters:
// - a_config: Pointer to a string containing the path to the Kubernetes config file.
// Returns:
// - (*kubernetes.Clientset): The created Kubernetes clientset.
// - (error): An error if any occurred during the clientset creation process.
func ConnectNow(a_config *string) (*kubernetes.Clientset, error) {
	config_built, err := CreateConfig(a_config)
	if err != nil {
		return nil, fmt.Errorf("Failed to get the *rest.Config: %w", err)
	}
	return NewK8sConnectionConfig(config_built)
}

// ContextSwitch creates a Kubernetes clientset by building the config with the specified context from a config file.
// Parameters:
// - contextName: The name of the Kubernetes context to switch to.
// - kubeconfig: Pointer to a string containing the path to the Kubernetes config file.
// Returns:
// - (*kubernetes.Clientset): The created Kubernetes clientset.
// - (error): An error if any occurred during the clientset creation process.
func ContextSwitch(contextName string, kubeconfig *string) (*kubernetes.Clientset, error) {
	config, err := BuildConfigWithContextFromFlags(contextName, *kubeconfig)
	if err != nil {
		return nil, fmt.Errorf("Failed to get the *rest.Config: %w", err)
	}

	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, fmt.Errorf("Failed to get the *kubernetes.Clientset: %w", err)
	}
	return clientset, nil
}

// buildConfigWithContextFromFlags creates a Kubernetes configuration by using the provided context and config file path.
// Parameters:
// - context: The name of the Kubernetes context to switch to.
// - kubeconfigPath: The path to the Kubernetes config file.
// Returns:
// - (*rest.Config): The built Kubernetes config.
// - (error): An error if any occurred during the config building process.
func BuildConfigWithContextFromFlags(context string, kubeconfigPath string) (*rest.Config, error) {
	return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
		&clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeconfigPath},
		&clientcmd.ConfigOverrides{
			CurrentContext: context,
		}).ClientConfig()
}

// ConnectToSource establishes a connection to a Kubernetes cluster specified by strSourceClusterContext.
// If strSourceClusterContext is provided, it switches the context to that cluster using the configFile.
// If strSourceClusterContext is empty, it connects to the current context using the configFile.
// It returns a Kubernetes clientset for the connected cluster and any error encountered during the connection.
func ConnectToSource(strSourceClusterContext string, configFile *string) (*kubernetes.Clientset, error) {
	var clientsetToSource *kubernetes.Clientset
	var err error
	if strSourceClusterContext != "" {
		clientsetToSource, err = ContextSwitch(strSourceClusterContext, configFile)
	} else {
		clientsetToSource, err = ConnectNow(configFile)
	}
	if err != nil {
		return nil, fmt.Errorf("Failed to get the *kubernetes.Clientset: %w", err)
	}
	return clientsetToSource, nil
}
07070100000027000081A400000000000000000000000165DC12FD00001533000000000000000000000000000000000000003200000000kube-kompare-0.0.2~alpha3/connect/connect_test.go// connect/connect_test.go

package connect

import (
	"os"
	"testing"

	"kompare/mock" // Import the mock package for testing

	"k8s.io/client-go/tools/clientcmd"
)

func TestCreateConfig(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes

	// Call CreateConfig with the path of the temporary kubeconfig file
	x := tempKubeconfig.Name()
	config, err := CreateConfig(&x)
	if err != nil {
		t.Fatalf("Error creating config: %v", err)
	}

	// Validate the created config
	if config == nil {
		t.Error("Expected non-nil config, got nil")
	}
	// Add more validation as needed, such as checking server URLs, etc.
}

func TestNewK8sConnectionConfig(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes

	// Create a mock configuration for testing
	x := tempKubeconfig.Name()
	config, err := CreateConfig(&x)
	if err != nil {
		t.Fatalf("Error creating config: %v", err)
	}

	// Call NewK8sConnectionConfig with the mock configuration
	clientset, err := NewK8sConnectionConfig(config)
	if err != nil {
		t.Fatalf("Error creating clientset: %v", err)
	}

	// Validate the created clientset
	if clientset == nil {
		t.Error("Expected non-nil clientset, got nil")
	}
}

func TestConnectNow(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes

	// Call CreateConfig with the path of the temporary kubeconfig file
	x := tempKubeconfig.Name()
	config, err := ConnectNow(&x)
	if err != nil {
		t.Fatalf("Error creating config: %v", err)
	}

	// Validate the created config
	if config == nil {
		t.Error("Expected non-nil config, got nil")
	}
	// Add more validation as needed, such as checking server URLs, etc.
}
func TestBuildConfigWithContextFromFlags(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes

	// Read the content of the kubeconfig file
	x, err := os.ReadFile(tempKubeconfig.Name())
	if err != nil {
		t.Fatalf("Error reading kubeconfig file: %v", err)
	}

	// Load the kubeconfig data
	kubeconfig, err := clientcmd.Load(x)
	if err != nil {
		t.Fatalf("Error loading kubeconfig: %v", err)
	}

	// Choose one of the contexts from the kubeconfig
	var testContext string
	for context := range kubeconfig.Contexts {
		testContext = context
		break // Choose the first context, you can modify this logic as needed
	}

	// Call BuildConfigWithContextFromFlags with the test context and temp kubeconfig path
	config, err := BuildConfigWithContextFromFlags(testContext, tempKubeconfig.Name())
	if err != nil {
		t.Fatalf("Error building config with context: %v", err)
	}

	// Validate the created config
	if config == nil {
		t.Error("Expected non-nil config, got nil")
	}

	// Add more validation if needed
}

func TestConnectToSource(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes
	// Read the content of the kubeconfig file
	tempKubeconfigByte, err := os.ReadFile(tempKubeconfig.Name())
	if err != nil {
		t.Fatalf("Error reading kubeconfig file: %v", err)
	}
	// Load the kubeconfig data
	kubeconfig, err := clientcmd.Load(tempKubeconfigByte)
	if err != nil {
		t.Fatalf("Error loading kubeconfig: %v", err)
	}

	// Choose one of the contexts from the kubeconfig
	var testContext string
	for context := range kubeconfig.Contexts {
		testContext = context
		break // Choose the first context, you can modify this logic as needed
	}
	x := tempKubeconfig.Name()
	config, err := ConnectToSource(testContext, &x)
	if err != nil {
		t.Fatalf("Error creating config: %v", err)
	}

	// Validate the created config
	if config == nil {
		t.Error("Expected non-nil config, got nil")
	}
	// Add more validation as needed, such as checking server URLs, etc.
}

func TestContextSwitch(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes
	// Read the content of the kubeconfig file
	tempKubeconfigByte, err := os.ReadFile(tempKubeconfig.Name())
	if err != nil {
		t.Fatalf("Error reading kubeconfig file: %v", err)
	}
	// Load the kubeconfig data
	kubeconfig, err := clientcmd.Load(tempKubeconfigByte)
	if err != nil {
		t.Fatalf("Error loading kubeconfig: %v", err)
	}

	// Choose one of the contexts from the kubeconfig
	var testContext string
	for context := range kubeconfig.Contexts {
		testContext = context
		break // Choose the first context, you can modify this logic as needed
	}
	x := tempKubeconfig.Name()
	config, err := ContextSwitch(testContext, &x)
	if err != nil {
		t.Fatalf("Error creating config: %v", err)
	}

	// Validate the created config
	if config == nil {
		t.Error("Expected non-nil config, got nil")
	}
	// Add more validation as needed, such as checking server URLs, etc.
}
07070100000028000081A400000000000000000000000165DC12FD000008A9000000000000000000000000000000000000002100000000kube-kompare-0.0.2~alpha3/go.modmodule kompare

go 1.21.6

require (
	github.com/akamensky/argparse v1.4.0
	github.com/go-test/deep v1.1.0
	github.com/gorilla/mux v1.8.1
	github.com/stretchr/testify v1.8.4
	golang.org/x/text v0.14.0
	k8s.io/api v0.29.1
	k8s.io/apiextensions-apiserver v0.26.3
	k8s.io/apimachinery v0.29.1
	k8s.io/client-go v0.29.1
)

require (
	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
	github.com/emicklei/go-restful/v3 v3.11.0 // indirect
	github.com/go-logr/logr v1.3.0 // indirect
	github.com/go-openapi/jsonpointer v0.19.6 // indirect
	github.com/go-openapi/jsonreference v0.20.2 // indirect
	github.com/go-openapi/swag v0.22.3 // indirect
	github.com/gogo/protobuf v1.3.2 // indirect
	github.com/golang/protobuf v1.5.3 // indirect
	github.com/google/gnostic-models v0.6.8 // indirect
	github.com/google/gofuzz v1.2.0 // indirect
	github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect
	github.com/google/uuid v1.3.1 // indirect
	github.com/imdario/mergo v0.3.12 // indirect
	github.com/josharian/intern v1.0.0 // indirect
	github.com/json-iterator/go v1.1.12 // indirect
	github.com/mailru/easyjson v0.7.7 // indirect
	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
	github.com/modern-go/reflect2 v1.0.2 // indirect
	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
	github.com/spf13/pflag v1.0.5 // indirect
	golang.org/x/net v0.19.0 // indirect
	golang.org/x/oauth2 v0.10.0 // indirect
	golang.org/x/sys v0.15.0 // indirect
	golang.org/x/term v0.15.0 // indirect
	golang.org/x/time v0.3.0 // indirect
	google.golang.org/appengine v1.6.7 // indirect
	google.golang.org/protobuf v1.31.0 // indirect
	gopkg.in/inf.v0 v0.9.1 // indirect
	gopkg.in/yaml.v2 v2.4.0 // indirect
	gopkg.in/yaml.v3 v3.0.1 // indirect
	k8s.io/klog/v2 v2.110.1 // indirect
	k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
	k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
	sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
	sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
	sigs.k8s.io/yaml v1.3.0 // indirect
)
07070100000029000081A400000000000000000000000165DC12FD00003B3E000000000000000000000000000000000000002100000000kube-kompare-0.0.2~alpha3/go.sumgithub.com/akamensky/argparse v1.4.0 h1:YGzvsTqCvbEZhL8zZu2AiA5nq805NZh75JNj4ajn1xc=
github.com/akamensky/argparse v1.4.0/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b h1:h9U78+dx9a4BKdQkBBos92HalKpaGKHrp+3Uo6yTodo=
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg=
github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8=
golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.29.1 h1:DAjwWX/9YT7NQD4INu49ROJuZAAAP/Ijki48GUPzxqw=
k8s.io/api v0.29.1/go.mod h1:7Kl10vBRUXhnQQI8YR/R327zXC8eJ7887/+Ybta+RoQ=
k8s.io/apiextensions-apiserver v0.26.3 h1:5PGMm3oEzdB1W/FTMgGIDmm100vn7IaUP5er36dB+YE=
k8s.io/apiextensions-apiserver v0.26.3/go.mod h1:jdA5MdjNWGP+njw1EKMZc64xAT5fIhN6VJrElV3sfpQ=
k8s.io/apimachinery v0.29.1 h1:KY4/E6km/wLBguvCZv8cKTeOwwOBqFNjwJIdMkMbbRc=
k8s.io/apimachinery v0.29.1/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU=
k8s.io/client-go v0.29.1 h1:19B/+2NGEwnFLzt0uB5kNJnfTsbV8w6TgQRz9l7ti7A=
k8s.io/client-go v0.29.1/go.mod h1:TDG/psL9hdet0TI9mGyHJSgRkW3H9JZk2dNEUS7bRks=
k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0=
k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo=
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
0707010000002A000081A400000000000000000000000165DC12FD0000340A000000000000000000000000000000000000002200000000kube-kompare-0.0.2~alpha3/main.gopackage main

import (
	"fmt"
	"kompare/cli"
	"kompare/compare"
	"kompare/connect"
	"kompare/query"
	"kompare/tools"
	"path/filepath"
	"strings"

	"golang.org/x/text/cases"
	"golang.org/x/text/language"
	v1 "k8s.io/api/core/v1"
	"k8s.io/client-go/kubernetes"
)

func main() {
	// Parse CLI arguments
	args := cli.PaserReader()
	if args.Err != nil {
		err := fmt.Errorf("error parsing arguments: %v", args.Err)
		panic(err)
	}
	if args.FileOutput != "" {
		defer tools.LogOutput(args.FileOutput)()
	}
	// var file *os.File
	// if args.FileOutput != "" {
	// 	_, fileString, _ := tools.IsValidPath(args.FileOutput)
	// 	var err error
	// 	file, err = os.Create(fileString)
	// 	if err != nil {
	// 		fmt.Println("Error opening file:", err)
	// 		os.Exit(1)
	// 	}
	// 	defer file.Close()
	// }
	// // Create a multi-writer to write to both stdout and the file (if specified)
	// var writers []io.Writer
	// writers = append(writers, os.Stdout)
	// if file != nil {
	// 	writers = append(writers, file)
	// }
	// multiWriter := io.MultiWriter(writers...)
	// // Use a goroutine to copy output to both stdout and the file
	// go func(out io.Writer) {
	// 	for {
	// 		// Copy output to both stdout and the file
	// 		_, err := io.Copy(out, os.Stdin)
	// 		if err != nil {
	// 			fmt.Println("Error copying output:", err)
	// 			return
	// 		}
	// 	}
	// }(multiWriter)

	// Connect to source cluster
	clientsetToSource, err := connect.ConnectToSource(args.SourceClusterContext, &args.KubeconfigFile)
	if err != nil {
		err = fmt.Errorf("error connecting to source cluster: %v", err)
		panic(err)
	}

	// Connect to target cluster
	clientsetToTarget, err := connect.ContextSwitch(args.TargetClusterContext, &args.KubeconfigFile)
	if err != nil {
		err = fmt.Errorf("error switching context: %v", err)
		panic(err)
	}

	// Determine namespace argument type
	var sourceNameSpacesList *v1.NamespaceList
	var sourceNameSpace *v1.Namespace
	namespaceArgType := DetectNamespacePattern(args.NamespaceName)
	switch namespaceArgType {
	case "specific":
		fmt.Println("Using", args.NamespaceName, "namespace")
		sourceNameSpace, err = query.GetNamespace(clientsetToSource, args.NamespaceName)
		if err != nil {
			err = fmt.Errorf("error listing namespaces: %v", err)
			panic(err)
		}
		sourceNameSpacesList = &v1.NamespaceList{Items: []v1.Namespace{*sourceNameSpace}}
	case "wildcard":
		sourceNameSpacesList, err = query.ListNameSpaces(clientsetToSource)
		if err != nil {
			err = fmt.Errorf("error listing namespaces: %v", err)
			panic(err)
		}
		sourceNameSpacesList = filterNamespaces(sourceNameSpacesList, args.NamespaceName)
	case "empty":
		iterateGoglabObjects(clientsetToSource, clientsetToTarget, args)
		sourceNameSpacesList, err = query.ListNameSpaces(clientsetToSource)
		if err != nil {
			err = fmt.Errorf("error listing namespaces: %v", err)
			panic(err)
		}
	}

	// Iterate over namespaces
	iterateNamespaces(sourceNameSpacesList, clientsetToSource, clientsetToTarget, args)

	fmt.Println("Finished all comparison works!")
}

func iterateGoglabObjects(clientsetToSource, clientsetToTarget *kubernetes.Clientset, args cli.ArgumentsReceivedValidated) bool {
	// Flag to track if any comparison was performed
	comparisonPerformed := false

	// Compare objects based on include list
	if args.Include != nil {
		includeObjects := []string{"namespace", "crd", "clusterrole", "clusterrolebinding"}
		for _, objectType := range includeObjects {
			if tools.IsInList(objectType, args.Include) {
				switch objectType {
				case "namespace":
					_, err := compare.CompareNameSpaces(clientsetToSource, clientsetToTarget, args)
					if err != nil {
						err = fmt.Errorf("error comparing Namespaces: %v", err)
						panic(err)
					}
				case "crd":
					_, err := compare.CompareCRDs(args.TargetClusterContext, args.KubeconfigFile, args)
					if err != nil {
						err = fmt.Errorf("error comparing CRDs: %v", err)
						panic(err)
					}
				case "clusterrole":
					_, err := compare.CompareClusterRoles(clientsetToSource, clientsetToTarget, args)
					if err != nil {
						err = fmt.Errorf("error comparing Cluster Role: %v", err)
						panic(err)
					}
				case "clusterrolebinding":
					_, err := compare.CompareClusterRoleBindings(clientsetToSource, clientsetToTarget, args)
					if err != nil {
						err = fmt.Errorf("error comparing Cluster Role: %v", err)
						panic(err)
					}
				}
				comparisonPerformed = true
			}
		}
	}

	// Compare objects based on exclude list
	if args.Exclude != nil {
		excludeObjects := []string{"namespace", "crd", "clusterrole", "clusterrolebinding"}
		for _, objectType := range excludeObjects {
			if !tools.IsInList(objectType, args.Exclude) {
				switch objectType {
				case "namespace":
					_, err := compare.CompareNameSpaces(clientsetToSource, clientsetToTarget, args)
					if err != nil {
						err = fmt.Errorf("Error comparing Namspace: %v", err)
						panic(err)
					}
				case "crd":
					_, err := compare.CompareCRDs(args.TargetClusterContext, args.KubeconfigFile, args)
					if err != nil {
						err = fmt.Errorf("Error comparing CRDs: %v", err)
						panic(err)
					}
				case "clusterrole":
					_, err := compare.CompareClusterRoles(clientsetToSource, clientsetToTarget, args)
					if err != nil {
						err = fmt.Errorf("Error comparing Cluster Role: %v", err)
						panic(err)
					}
				case "clusterrolebinding":
					_, err := compare.CompareClusterRoleBindings(clientsetToSource, clientsetToTarget, args)
					if err != nil {
						err = fmt.Errorf("Error comparing Cluster Role Binding: %v", err)
						panic(err)
					}
				}
				comparisonPerformed = true
			}
		}
	}

	// If no include or exclude lists are provided, perform default comparisons
	if args.Include == nil && args.Exclude == nil {
		_, err := compare.CompareNameSpaces(clientsetToSource, clientsetToTarget, args)
		if err != nil {
			err = fmt.Errorf("error comparing Namespaces: %v", err)
			panic(err)
		}
		_, err = compare.CompareCRDs(args.TargetClusterContext, args.KubeconfigFile, args)
		if err != nil {
			err = fmt.Errorf("error comparing CRDs: %v", err)
			panic(err)
		}
		_, err = compare.CompareClusterRoles(clientsetToSource, clientsetToTarget, args)
		if err != nil {
			err = fmt.Errorf("error comparing Cluster Roles: %v", err)
			panic(err)
		}
		_, err = compare.CompareClusterRoleBindings(clientsetToSource, clientsetToTarget, args)
		if err != nil {
			err = fmt.Errorf("error comparing Cluster Role Bindings: %v", err)
			panic(err)
		}
		comparisonPerformed = true
	}

	// Print completion message if any comparison was performed
	if comparisonPerformed {
		fmt.Println("Done comparing Kubernetes global objects.")
	}
	return comparisonPerformed
}

func compareAllResourcesInNamespace(clientsetToSource, clientsetToTarget *kubernetes.Clientset, namespace string, TheArgs cli.ArgumentsReceivedValidated) {
	fmt.Printf("Looping on Namespace: %s\n", namespace)
	// Compare all resources for the namespace
	resources := []string{"deployment", "ingress", "service", "serviceaccount", "configmap", "secret", "role", "rolebinding", "hpa", "cronjob", "networkpolicy"}

	// Create a title case converter for English
	titleCase := cases.Title(language.English)

	for _, resource := range resources {
		titleResource := titleCase.String(resource)
		fmt.Printf("%s\n", titleResource)
		compareResource(clientsetToSource, clientsetToTarget, namespace, resource, TheArgs)
		fmt.Printf("Finished %s for namespace: %s\n", titleResource, namespace)
	}

	fmt.Printf("... Done with all resources in ns: %s.\n", namespace)
}

func compareResourcesByLists(clientsetToSource, clientsetToTarget *kubernetes.Clientset, namespace string, TheArgs cli.ArgumentsReceivedValidated) {
	fmt.Printf("Looping namespace: %s\n", namespace)

	includeResources := TheArgs.Include
	excludeResources := TheArgs.Exclude

	// Create a title case converter for English
	titleCase := cases.Title(language.English)

	// Define all resources
	resources := []string{"deployment", "ingress", "service", "serviceaccout", "configmap", "secret", "role", "rolebinding", "networkpolicy", "hpa", "cronjob"}

	// Compare resources based on include list
	for _, resource := range includeResources {
		titleResource := titleCase.String(resource)
		fmt.Printf("%s\n", titleResource)
		compareResource(clientsetToSource, clientsetToTarget, namespace, resource, TheArgs)
		fmt.Printf("Finished %s for namespace: %s\n", titleResource, namespace)

	}

	// Compare resources based on exclude list
	if excludeResources != nil {
		for _, resource := range resources {
			// Check if resource is not in the exclude list
			if !tools.IsInList(resource, excludeResources) {
				titleResource := titleCase.String(resource)
				fmt.Printf("%s\n", titleResource)
				compareResource(clientsetToSource, clientsetToTarget, namespace, resource, TheArgs)
				fmt.Printf("Finished %s for namespace: %s\n", titleResource, namespace)
			}
		}
	}
}

func compareResource(clientsetToSource, clientsetToTarget *kubernetes.Clientset, namespace, resource string, TheArgs cli.ArgumentsReceivedValidated) {
	switch resource {
	case "deployment":
		_, err := compare.CompareDeployments(clientsetToSource, clientsetToTarget, namespace, TheArgs)
		if err != nil {
			err = fmt.Errorf("error comparing Deployments: %v", err)
			panic(err)
		}
	case "ingress":
		_, err := compare.CompareIngresses(clientsetToSource, clientsetToTarget, namespace, TheArgs)
		if err != nil {
			err = fmt.Errorf("error comparing Ingresses: %v", err)
			panic(err)
		}
	case "service":
		_, err := compare.CompareServices(clientsetToSource, clientsetToTarget, namespace, TheArgs)
		if err != nil {
			err = fmt.Errorf("error comparing Services: %v", err)
			panic(err)
		}
	case "serviceaccount":
		_, err := compare.CompareServiceAccounts(clientsetToSource, clientsetToTarget, namespace, TheArgs)
		if err != nil {
			err = fmt.Errorf("error comparing Service Accounts: %v", err)
			panic(err)
		}
	case "configmap":
		_, err := compare.CompareConfigMaps(clientsetToSource, clientsetToTarget, namespace, TheArgs)
		if err != nil {
			err = fmt.Errorf("error comparing Config Maps: %v", err)
			panic(err)
		}
	case "secret":
		_, err := compare.CompareSecrets(clientsetToSource, clientsetToTarget, namespace, TheArgs)
		if err != nil {
			err = fmt.Errorf("error comparing Secrets: %v", err)
			panic(err)
		}
	case "role":
		_, err := compare.CompareRoles(clientsetToSource, clientsetToTarget, namespace, TheArgs)
		if err != nil {
			err = fmt.Errorf("error comparing Roles: %v", err)
			panic(err)
		}
	case "rolebinding":
		_, err := compare.CompareRoleBindings(clientsetToSource, clientsetToTarget, namespace, TheArgs)
		if err != nil {
			err = fmt.Errorf("error comparing Role Bindings: %v", err)
			panic(err)
		}
	case "hpa":
		_, err := compare.CompareHPAs(clientsetToSource, clientsetToTarget, namespace, TheArgs)
		if err != nil {
			err = fmt.Errorf("error comparing Horizontal Pod Autoscalers: %v", err)
			panic(err)
		}
	case "cronjob":
		_, err := compare.CompareCronJobs(clientsetToSource, clientsetToTarget, namespace, TheArgs)
		if err != nil {
			err = fmt.Errorf("error comparing Cron Jobs: %v", err)
			panic(err)
		}
	case "networkpolicy":
		_, err := compare.CompareNetworkPolicies(clientsetToSource, clientsetToTarget, namespace, TheArgs)
		if err != nil {
			err = fmt.Errorf("error comparing Network Policies: %v", err)
			panic(err)
		}
	}
}

func iterateNamespaces(sourceNameSpacesList *v1.NamespaceList, clientsetToSource, clientsetToTarget *kubernetes.Clientset, TheArgs cli.ArgumentsReceivedValidated) {
	// Check if include or exclude lists are provided, or if no specific lists are provided
	if TheArgs.Include == nil && TheArgs.Exclude == nil {
		// If no include or exclude lists are provided, compare all resources for each namespace
		for _, ns := range sourceNameSpacesList.Items {
			compareAllResourcesInNamespace(clientsetToSource, clientsetToTarget, ns.Name, TheArgs)
		}
	} else {
		// Compare resources based on include or exclude lists
		resources := []string{"deployment", "ingress", "service", "serviceaccount", "configmap", "secret", "role", "rolebinding", "hpa", "cronjob", "networkpolicy"}
		if tools.AreAnyInLists(TheArgs.Include, resources) || tools.AreAnyInLists(TheArgs.Exclude, resources) {
			for _, ns := range sourceNameSpacesList.Items {
				compareResourcesByLists(clientsetToSource, clientsetToTarget, ns.Name, TheArgs)
			}
		} else {
			fmt.Println("No namespaced resources to compare")
		}
	}
}

// filterNamespaces filters namespaces based on the wildcard pattern
func filterNamespaces(namespaces *v1.NamespaceList, pattern string) *v1.NamespaceList {
	matchingNamespaces := v1.NamespaceList{
		Items: []v1.Namespace{},
	}
	for _, ns := range namespaces.Items {
		if matchWildcard(ns.Name, pattern) {
			matchingNamespaces.Items = append(matchingNamespaces.Items, ns)
		}
	}
	return &matchingNamespaces
}

// matchWildcard checks if a string matches the wildcard pattern
func matchWildcard(s, pattern string) bool {
	match, err := filepath.Match(pattern, s)
	if err != nil {
		return false
	}
	return match
}

func DetectNamespacePattern(pattern string) string {
	if pattern == "" {
		return "empty"
	} else if strings.Contains(pattern, "*") {
		return "wildcard"
	} else {
		return "specific"
	}
}
0707010000002B000081A400000000000000000000000165DC12FD00000FA7000000000000000000000000000000000000002700000000kube-kompare-0.0.2~alpha3/main_test.gopackage main

import (
	"fmt"
	"os"
	"testing"

	"kompare/mock"

	"github.com/stretchr/testify/assert"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestMain(t *testing.T) {
	// Redirect standard output to /dev/null
	os.Stdout, _ = os.Open(os.DevNull)
	defer func() {
		os.Stdout = os.NewFile(1, "/dev/stdout")
	}()

	// Simulate a parsing error
	os.Args = []string{"main.go", "--invalid-flag"}
	assert.Panics(t, func() { main() }, "Expected a panic due to parsing error")

	// Simulate connection errors
	os.Args = []string{"main.go"}
	assert.Panics(t, func() { main() }, "Expected a panic due to connection error")

	// Simulate namespace listing errors
	os.Args = []string{"main.go", "-s", "source-context", "-t", "target-context", "-n", "InvalidNS"}
	assert.Panics(t, func() { main() }, "Expected a panic due to namespace listing error")

	_, _, kubeconfigFile := mock.SetupTestEnvironment()

	// Set up command-line arguments
	os.Args = []string{"main.go", "-t", "target-context", "-s", "source-context", "-c", kubeconfigFile.Name()}

	// Capture errors from main function
	var capturedError error

	// Run the main function and capture any errors
	func() {
		defer func() {
			if r := recover(); r != nil {
				capturedError = fmt.Errorf("panic occurred: %v", r)
			}
		}()
		main()
	}()

	assert.NoError(t, capturedError, "Expected no errors during main function execution")
	// Run the main function and capture any errors
	func() {
		defer func() {
			if r := recover(); r != nil {
				capturedError = fmt.Errorf("panic occurred: %v", r)
			}
		}()
		main()
	}()

	// Assert that clientsetToSource and clientsetToTarget are not nil after connecting to clusters
	fmt.Println("Test completed")
}

func TestMatchWildcard(t *testing.T) {
	// Test case when the string matches the wildcard pattern
	result := matchWildcard("hello", "h*llo")
	if !result {
		t.Error("Expected true, but got false")
	}

	// Test case when the string does not match the wildcard pattern
	result = matchWildcard("world", "h*llo")
	if result {
		t.Error("Expected false, but got true")
	}

	// Test case when there is an error in pattern matching
	result = matchWildcard("hello", "[")
	if result {
		t.Error("Expected false, but got true")
	}
}

func TestDetectNamespacePattern(t *testing.T) {
	// Test case for empty pattern
	result := DetectNamespacePattern("")
	if result != "empty" {
		t.Errorf("Expected 'empty' but got '%s'", result)
	}

	// Test case for wildcard pattern
	result = DetectNamespacePattern("*.example.com")
	if result != "wildcard" {
		t.Errorf("Expected 'wildcard' but got '%s'", result)
	}

	// Test case for specific pattern
	result = DetectNamespacePattern("example.com")
	if result != "specific" {
		t.Errorf("Expected 'specific' but got '%s'", result)
	}
}

func TestFilterNamespaces(t *testing.T) {
	// Define test data
	namespaces := &v1.NamespaceList{
		Items: []v1.Namespace{
			{
				ObjectMeta: metav1.ObjectMeta{Name: "default"},
			},
			{
				ObjectMeta: metav1.ObjectMeta{Name: "kube-system"},
			},
			{
				ObjectMeta: metav1.ObjectMeta{Name: "test-namespace"},
			},
		},
	}

	// Define test cases
	testCases := []struct {
		name           string
		pattern        string
		expectedResult int
	}{
		{"MatchAll", "*", 3},
		{"MatchSpecific", "kube-*", 1},
		{"NoMatch", "nonexistent-*", 0},
	}

	// Iterate over test cases
	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			// Call the function under test
			filtered := filterNamespaces(namespaces, tc.pattern)

			// Check the length of the filtered namespaces
			if len(filtered.Items) != tc.expectedResult {
				t.Errorf("Expected %d namespaces matching pattern '%s', got %d", tc.expectedResult, tc.pattern, len(filtered.Items))
			}

			// Ensure all filtered namespaces match the pattern
			for _, ns := range filtered.Items {
				if !matchWildcard(ns.Name, tc.pattern) {
					t.Errorf("Namespace '%s' does not match pattern '%s'", ns.Name, tc.pattern)
				}
			}
		})
	}
}
0707010000002C000041ED00000000000000000000000265DC12FD00000000000000000000000000000000000000000000001F00000000kube-kompare-0.0.2~alpha3/mock0707010000002D000081A400000000000000000000000165DC12FD0000865D000000000000000000000000000000000000002600000000kube-kompare-0.0.2~alpha3/mock/k8s.gopackage mock

import (
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"time"

	"os"

	"github.com/gorilla/mux"
	appsv1 "k8s.io/api/apps/v1"
	autoscalingv1 "k8s.io/api/autoscaling/v1"
	batchv1 "k8s.io/api/batch/v1"
	Corev1 "k8s.io/api/core/v1"
	v1 "k8s.io/api/core/v1"
	networkingv1 "k8s.io/api/networking/v1"
	RbacV1 "k8s.io/api/rbac/v1"
	apiextensionv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func StartMockCluster() (string, *mux.Router, error) {
	r := mux.NewRouter()

	// Routes for different Kubernetes resources
	r.HandleFunc("/apis/apps/v1/namespaces/{namespace}/deployments", GetDeployments).Methods("GET")
	r.HandleFunc("/apis/networking.k8s.io/v1/namespaces/{namespace}/ingresses", GetIngresses).Methods("GET")
	r.HandleFunc("/api/v1/namespaces/{namespace}/secrets", GetSecrets).Methods("GET")
	r.HandleFunc("/api/v1/namespaces/{namespace}/configmaps", GetConfigMaps).Methods("GET")
	r.HandleFunc("/api/v1/namespaces/{namespace}/services", GetServices).Methods("GET")
	r.HandleFunc("/apis/autoscaling/v1/namespaces/{namespace}/horizontalpodautoscalers", GetHPAs).Methods("GET")
	r.HandleFunc("/apis/batch/v1/namespaces/{namespace}/cronjobs", GetCronJobs).Methods("GET")
	r.HandleFunc("/api/v1/namespaces", GetNamespaces).Methods("GET")
	r.HandleFunc("/api/v1/namespaces/namespace2", GetNamespace).Methods("GET")
	r.HandleFunc("/apis/rbac.authorization.k8s.io/v1/namespaces/{namespace}/roles", GetRoles).Methods("GET")
	r.HandleFunc("/apis/rbac.authorization.k8s.io/v1/namespaces/{namespace}/rolebindings", GetRoleBindings).Methods("GET")
	r.HandleFunc("/apis/apiextensions.k8s.io/v1/customresourcedefinitions", GetCustomResourceDefinitions).Methods("GET")
	r.HandleFunc("/apis/rbac.authorization.k8s.io/v1/clusterroles", GetClusterRoles).Methods("GET")
	r.HandleFunc("/apis/rbac.authorization.k8s.io/v1/clusterrolebindings", GetClusterRoleBindings).Methods("GET")
	r.HandleFunc("/api/v1/namespaces/{namespace}/serviceaccounts", GetServiceAccounts).Methods("GET")
	r.HandleFunc("/apis/networking.k8s.io/v1/namespaces/{namespace}/networkpolicies", GetNetworkPolicies).Methods("GET")

	// Create a HTTP server instance
	server := &http.Server{
		Addr:         ":0", // Use port 0 for dynamic allocation
		Handler:      r,
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 10 * time.Second,
	}

	// Create a TCP listener
	listener, err := net.Listen("tcp", ":0") // Use port 0 for dynamic allocation
	if err != nil {
		return "", nil, fmt.Errorf("error creating listener: %v", err)
	}

	// Get the port
	port := listener.Addr().(*net.TCPAddr).Port
	clusterURL := fmt.Sprintf("http://localhost:%d", port)

	// Start serving using the HTTP server
	go func() {
		if err := server.Serve(listener); err != nil && err != http.ErrServerClosed {
			fmt.Printf("Error serving mock cluster: %v\n", err)
			os.Exit(1)
		}
	}()

	fmt.Println("Server is running...")
	fmt.Println("Cluster URL:", clusterURL)

	return clusterURL, r, nil
}

// GetNamespace handles requests to /api/v1/namespaces/{name}
func GetNamespace(w http.ResponseWriter, r *http.Request) {
	// Define the namespace
	namespace := v1.Namespace{
		ObjectMeta: metav1.ObjectMeta{
			Name: "namespace2",
		},
	}

	// Marshal namespace to JSON
	namespaceJSON, err := json.Marshal(namespace)
	if err != nil {
		http.Error(w, fmt.Sprintf("Error marshaling namespace to JSON: %v", err), http.StatusInternalServerError)
		return
	}

	// Set Content-Type header
	w.Header().Set("Content-Type", "application/json")

	// Write JSON response
	_, err = w.Write(namespaceJSON)
	if err != nil {
		http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
		return
	}
}

// NamespacesHandler handles requests to /api/v1/namespaces
func GetNamespaces(w http.ResponseWriter, r *http.Request) {
	// Define a sample list of namespaces
	namespaces := &v1.NamespaceList{
		Items: []v1.Namespace{
			{
				ObjectMeta: metav1.ObjectMeta{
					Name: "namespace1",
				},
			},
			{
				ObjectMeta: metav1.ObjectMeta{
					Name: "namespace2",
				},
			},
			{
				ObjectMeta: metav1.ObjectMeta{
					Name: "namespace3",
				},
			},
		},
	}

	// Convert the NamespaceList to JSON
	responseJSON, err := json.Marshal(namespaces)
	if err != nil {
		http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
		return
	}

	// Set the response headers
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)

	// Write the JSON response to the client
	_, err = w.Write(responseJSON)
	if err != nil {
		http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
		return
	}
}

func GetDeployments(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	namespace := vars["namespace"]

	// Check if the namespace is "namespace2"
	if namespace == "namespace2" {
		// Create three sample deployments for namespace2
		deployments := &appsv1.DeploymentList{
			ListMeta: metav1.ListMeta{
				ResourceVersion: "320850103", // Set a sample resource version
			},
			Items: []appsv1.Deployment{
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "deployment1",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "deployment2",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "deployment3",
						Namespace: "namespace2",
					},
				},
			},
		}

		// Convert the DeploymentList object to JSON
		jsonResponse, err := json.Marshal(deployments)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	} else {
		// If the namespace is not "namespace2", return an empty list of deployments
		deployments := &appsv1.DeploymentList{
			ListMeta: metav1.ListMeta{
				ResourceVersion: "0",
			},
			Items: []appsv1.Deployment{},
		}

		// Convert the DeploymentList object to JSON
		jsonResponse, err := json.Marshal(deployments)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	}
}

// GetHPAs handles HTTP requests to retrieve HorizontalPodAutoscaler resources.
func GetHPAs(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	namespace := vars["namespace"]

	// Check if the namespace is "namespace2"
	if namespace == "namespace2" {
		// Create three sample HPAs for namespace2
		hpas := &autoscalingv1.HorizontalPodAutoscalerList{
			ListMeta: metav1.ListMeta{
				ResourceVersion: "320850103", // Set a sample resource version
			},
			Items: []autoscalingv1.HorizontalPodAutoscaler{
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "hpa1",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "hpa2",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "hpa3",
						Namespace: "namespace2",
					},
				},
			},
		}

		// Convert the HPAList object to JSON
		jsonResponse, err := json.Marshal(hpas)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	} else {
		// If the namespace is not "namespace2", return an empty list of HPAs
		hpas := &autoscalingv1.HorizontalPodAutoscalerList{
			ListMeta: metav1.ListMeta{
				ResourceVersion: "0",
			},
			Items: []autoscalingv1.HorizontalPodAutoscaler{},
		}

		// Convert the HPAList object to JSON
		jsonResponse, err := json.Marshal(hpas)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	}
}

// GetCronJobs handles HTTP requests to retrieve CronJob resources.
func GetCronJobs(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	namespace := vars["namespace"]

	// Check if the namespace is "namespace2"
	if namespace == "namespace2" {
		// Create three sample CronJobs for namespace2
		cronJobs := &batchv1.CronJobList{
			TypeMeta: metav1.TypeMeta{
				Kind:       "CronJobList",
				APIVersion: "batch/v1",
			},
			Items: []batchv1.CronJob{
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "cronjob1",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "cronjob2",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "cronjob3",
						Namespace: "namespace2",
					},
				},
			},
		}

		// Convert the CronJobList object to JSON
		jsonResponse, err := json.Marshal(cronJobs)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	} else {
		// If the namespace is not "namespace2", return an empty list of CronJobs
		cronJobs := &batchv1.CronJobList{
			TypeMeta: metav1.TypeMeta{
				Kind:       "CronJobList",
				APIVersion: "batch/v1",
			},
			Items: []batchv1.CronJob{},
		}

		// Convert the CronJobList object to JSON
		jsonResponse, err := json.Marshal(cronJobs)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	}
}

// GetCustomResourceDefinitions handles HTTP requests to retrieve Custom Resource Definitions (CRDs).
func GetCustomResourceDefinitions(w http.ResponseWriter, r *http.Request) {
	// Sample response for the CRDList
	crdList := &apiextensionv1.CustomResourceDefinitionList{
		TypeMeta: metav1.TypeMeta{
			Kind:       "CustomResourceDefinitionList",
			APIVersion: "apiextensions.k8s.io/v1",
		},
		Items: []apiextensionv1.CustomResourceDefinition{
			{
				ObjectMeta: metav1.ObjectMeta{
					Name: "crd1",
				},
				// Add more details for CRD1 as needed
			},
			{
				ObjectMeta: metav1.ObjectMeta{
					Name: "crd2",
				},
				// Add more details for CRD2 as needed
			},
			{
				ObjectMeta: metav1.ObjectMeta{
					Name: "crd3",
				},
				// Add more details for CRD3 as needed
			},
		},
	}

	// Convert the CRDList object to JSON
	jsonResponse, err := json.Marshal(crdList)
	if err != nil {
		http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
		return
	}

	// Set the response headers and write the JSON response
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	_, err = w.Write(jsonResponse)
	if err != nil {
		http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
		return
	}
}

func GetIngresses(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	namespace := vars["namespace"]

	// Check if the namespace is "namespace2"
	if namespace == "namespace2" {
		// Create three sample ingresses for namespace2
		ingresses := &networkingv1.IngressList{
			ListMeta: metav1.ListMeta{
				ResourceVersion: "320850103", // Set a sample resource version
			},
			Items: []networkingv1.Ingress{
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "ingress1",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "ingress2",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "ingress3",
						Namespace: "namespace2",
					},
				},
			},
		}

		// Convert the IngressList object to JSON
		jsonResponse, err := json.Marshal(ingresses)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	} else {
		// If the namespace is not "namespace2", return an empty list of ingresses
		ingresses := &networkingv1.IngressList{
			ListMeta: metav1.ListMeta{
				ResourceVersion: "0",
			},
			Items: []networkingv1.Ingress{},
		}

		// Convert the IngressList object to JSON
		jsonResponse, err := json.Marshal(ingresses)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	}
}

// GetSecrets handles HTTP requests to retrieve Secrets.
func GetSecrets(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	namespace := vars["namespace"]

	// Check if the namespace is "namespace2"
	if namespace == "namespace2" {
		// Create three sample secrets for namespace2
		secrets := &Corev1.SecretList{
			ListMeta: metav1.ListMeta{
				ResourceVersion: "320850103", // Set a sample resource version
			},
			Items: []Corev1.Secret{
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "secret1",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "secret2",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "secret3",
						Namespace: "namespace2",
					},
				},
			},
		}

		// Convert the SecretList object to JSON
		jsonResponse, err := json.Marshal(secrets)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	} else {
		// If the namespace is not "namespace2", return an empty list of secrets
		secrets := &Corev1.SecretList{
			ListMeta: metav1.ListMeta{
				ResourceVersion: "0",
			},
			Items: []Corev1.Secret{},
		}

		// Convert the SecretList object to JSON
		jsonResponse, err := json.Marshal(secrets)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	}
}

// GetConfigMaps handles HTTP requests to retrieve ConfigMaps.
func GetConfigMaps(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	namespace := vars["namespace"]

	// Check if the namespace is "namespace2"
	if namespace == "namespace2" {
		// Create three sample config maps for namespace2
		configMaps := &Corev1.ConfigMapList{
			ListMeta: metav1.ListMeta{
				ResourceVersion: "320850103", // Set a sample resource version
			},
			Items: []Corev1.ConfigMap{
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "configmap1",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "configmap2",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "configmap3",
						Namespace: "namespace2",
					},
				},
			},
		}

		// Convert the ConfigMapList object to JSON
		jsonResponse, err := json.Marshal(configMaps)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	} else {
		// If the namespace is not "namespace2", return an empty list of config maps
		configMaps := &Corev1.ConfigMapList{
			ListMeta: metav1.ListMeta{
				ResourceVersion: "0",
			},
			Items: []Corev1.ConfigMap{},
		}

		// Convert the ConfigMapList object to JSON
		jsonResponse, err := json.Marshal(configMaps)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	}
}

func GetServices(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	namespace := vars["namespace"]

	// Check if the namespace is "namespace2"
	if namespace == "namespace2" {
		// Create three sample services for namespace2
		services := &Corev1.ServiceList{
			ListMeta: metav1.ListMeta{
				ResourceVersion: "320850103", // Set a sample resource version
			},
			Items: []Corev1.Service{
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "service1",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "service2",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "service3",
						Namespace: "namespace2",
					},
				},
			},
		}

		// Convert the ServiceList object to JSON
		jsonResponse, err := json.Marshal(services)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	} else {
		// If the namespace is not "namespace2", return an empty list of services
		services := &Corev1.ServiceList{
			ListMeta: metav1.ListMeta{
				ResourceVersion: "0",
			},
			Items: []Corev1.Service{},
		}

		// Convert the ServiceList object to JSON
		jsonResponse, err := json.Marshal(services)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	}
}

func GetNetworkPolicies(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	namespace := vars["namespace"]

	// Check if the namespace is "namespace2"
	if namespace == "namespace2" {
		// Create three sample network policies for namespace2
		networkPolicies := &networkingv1.NetworkPolicyList{
			ListMeta: metav1.ListMeta{
				ResourceVersion: "320850103", // Set a sample resource version
			},
			Items: []networkingv1.NetworkPolicy{
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "networkpolicy1",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "networkpolicy2",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "networkpolicy3",
						Namespace: "namespace2",
					},
				},
			},
		}

		// Convert the NetworkPolicyList object to JSON
		jsonResponse, err := json.Marshal(networkPolicies)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	} else {
		// If the namespace is not "namespace2", return an empty list of network policies
		networkPolicies := &networkingv1.NetworkPolicyList{
			ListMeta: metav1.ListMeta{
				ResourceVersion: "0",
			},
			Items: []networkingv1.NetworkPolicy{},
		}

		// Convert the NetworkPolicyList object to JSON
		jsonResponse, err := json.Marshal(networkPolicies)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	}
}

func SetupTestEnvironment() (string, string, *os.File) {
	// Set up temporary kubeconfig file with mock cluster URLs
	sourceClusterURL, _, _ := StartMockCluster()
	targetClusterURL, _, _ := StartMockCluster()

	kubeconfigData := []byte(fmt.Sprintf(`
apiVersion: v1
clusters:
- cluster:
    server: %s
  name: source-context
- cluster:
    server: %s
  name: target-context
contexts:
- context:
    cluster: source-context
    user: ""
  name: source-context
- context:
    cluster: target-context
    user: ""
  name: target-context
current-context: source-context
`, sourceClusterURL, targetClusterURL))

	tempKubeconfig, err := os.CreateTemp("", "kubeconfig")
	if err != nil {
		panic(fmt.Sprintf("Error creating temporary kubeconfig: %v", err))
	}
	// defer os.Remove(tempKubeconfig.Name())

	_, err = tempKubeconfig.Write(kubeconfigData)
	if err != nil {
		panic(fmt.Sprintf("Error writing kubeconfig data: %v", err))
	}

	return sourceClusterURL, targetClusterURL, tempKubeconfig
}

// GetServiceAccounts handles HTTP requests to retrieve Service Accounts.
func GetServiceAccounts(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	namespace := vars["namespace"]

	// Check if the namespace is "namespace2"
	if namespace == "namespace2" {
		// Create three sample service accounts for namespace2
		serviceAccounts := &Corev1.ServiceAccountList{
			ListMeta: metav1.ListMeta{
				ResourceVersion: "320850103", // Set a sample resource version
			},
			Items: []Corev1.ServiceAccount{
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "serviceaccount1",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "serviceaccount2",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "serviceaccount3",
						Namespace: "namespace2",
					},
				},
			},
		}

		// Convert the ServiceAccountList object to JSON
		jsonResponse, err := json.Marshal(serviceAccounts)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	} else {
		// If the namespace is not "namespace2", return an empty list of service accounts
		serviceAccounts := &Corev1.ServiceAccountList{
			ListMeta: metav1.ListMeta{
				ResourceVersion: "0",
			},
			Items: []Corev1.ServiceAccount{},
		}

		// Convert the ServiceAccountList object to JSON
		jsonResponse, err := json.Marshal(serviceAccounts)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	}
}

// GetRoles handles HTTP requests to retrieve Roles.
func GetRoles(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	namespace := vars["namespace"]

	// Check if the namespace is "namespace2"
	if namespace == "namespace2" {
		// Create three sample roles for namespace2
		roles := &RbacV1.RoleList{
			ListMeta: metav1.ListMeta{
				ResourceVersion: "320850103", // Set a sample resource version
			},
			Items: []RbacV1.Role{
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "role1",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "role2",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "role3",
						Namespace: "namespace2",
					},
				},
			},
		}

		// Convert the RoleList object to JSON
		jsonResponse, err := json.Marshal(roles)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	} else {
		// If the namespace is not "namespace2", return an empty list of roles
		roles := &RbacV1.RoleList{
			ListMeta: metav1.ListMeta{
				ResourceVersion: "0",
			},
			Items: []RbacV1.Role{},
		}

		// Convert the RoleList object to JSON
		jsonResponse, err := json.Marshal(roles)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	}
}

// GetRoleBindings handles HTTP requests to retrieve RoleBinding resources.
func GetRoleBindings(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	namespace := vars["namespace"]

	// Check if the namespace is "namespace2"
	if namespace == "namespace2" {
		// Create three sample role bindings for namespace2
		roleBindings := &RbacV1.RoleBindingList{
			TypeMeta: metav1.TypeMeta{
				Kind:       "RoleBindingList",
				APIVersion: "rbac.authorization.k8s.io/v1",
			},
			Items: []RbacV1.RoleBinding{
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "rolebinding1",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "rolebinding2",
						Namespace: "namespace2",
					},
				},
				{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "rolebinding3",
						Namespace: "namespace2",
					},
				},
			},
		}

		// Convert the RoleBindingList object to JSON
		jsonResponse, err := json.Marshal(roleBindings)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	} else {
		// Sample response for the RoleBindingList
		roleBindings := &RbacV1.RoleBindingList{
			TypeMeta: metav1.TypeMeta{
				Kind:       "RoleBindingList",
				APIVersion: "rbac.authorization.k8s.io/v1",
			},
			Items: []RbacV1.RoleBinding{}, // Placeholder for RoleBinding items
		}

		// Convert the RoleBindingList object to JSON
		jsonResponse, err := json.Marshal(roleBindings)
		if err != nil {
			http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
			return
		}

		// Set the response headers and write the JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		_, err = w.Write(jsonResponse)
		if err != nil {
			http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
			return
		}
	}
}

// GetClusterRoles handles HTTP requests to retrieve ClusterRoles.
func GetClusterRoles(w http.ResponseWriter, r *http.Request) {
	// Create three sample cluster roles
	clusterRoles := &RbacV1.ClusterRoleList{
		TypeMeta: metav1.TypeMeta{
			Kind:       "ClusterRoleList",
			APIVersion: "rbac.authorization.k8s.io/v1",
		},
		Items: []RbacV1.ClusterRole{
			{
				// ClusterRole 1
				TypeMeta: metav1.TypeMeta{
					Kind:       "ClusterRole",
					APIVersion: "rbac.authorization.k8s.io/v1",
				},
				ObjectMeta: metav1.ObjectMeta{
					Name:            "clusterroleNAMEWITHNUMBER1",
					ResourceVersion: "320850103", // Same as the previous resource version
				},
				// Add rules, etc. for ClusterRole 1
			},
			{
				// ClusterRole 2
				TypeMeta: metav1.TypeMeta{
					Kind:       "ClusterRole",
					APIVersion: "rbac.authorization.k8s.io/v1",
				},
				ObjectMeta: metav1.ObjectMeta{
					Name:            "clusterroleNAMEWITHNUMBER2",
					ResourceVersion: "320850103", // Same as the previous resource version
				},
				// Add rules, etc. for ClusterRole 2
			},
			{
				// ClusterRole 3
				TypeMeta: metav1.TypeMeta{
					Kind:       "ClusterRole",
					APIVersion: "rbac.authorization.k8s.io/v1",
				},
				ObjectMeta: metav1.ObjectMeta{
					Name:            "clusterroleNAMEWITHNUMBER3",
					ResourceVersion: "320850103", // Same as the previous resource version
				},
				// Add rules, etc. for ClusterRole 3
			},
		},
	}

	// Convert the ClusterRoleList object to JSON
	jsonResponse, err := json.Marshal(clusterRoles)
	if err != nil {
		http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
		return
	}

	// Set the response headers and write the JSON response
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	_, err = w.Write(jsonResponse)
	if err != nil {
		http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
		return
	}
}

// GetClusterRoleBindings handles HTTP requests to retrieve ClusterRoleBinding resources.
func GetClusterRoleBindings(w http.ResponseWriter, r *http.Request) {
	// Sample response for the ClusterRoleBindingList
	clusterRoleBindings := &RbacV1.ClusterRoleBindingList{
		TypeMeta: metav1.TypeMeta{
			Kind:       "ClusterRoleBindingList",
			APIVersion: "rbac.authorization.k8s.io/v1",
		},
		Items: []RbacV1.ClusterRoleBinding{
			{
				// ClusterRoleBinding 1
				TypeMeta: metav1.TypeMeta{
					Kind:       "ClusterRoleBinding",
					APIVersion: "rbac.authorization.k8s.io/v1",
				},
				ObjectMeta: metav1.ObjectMeta{
					Name:            "clusterrolebinding1",
					ResourceVersion: "320850103", // Same as the previous resource version
				},
				// Add roleRef, subjects, etc. for ClusterRoleBinding 1
			},
			{
				// ClusterRoleBinding 2
				TypeMeta: metav1.TypeMeta{
					Kind:       "ClusterRoleBinding",
					APIVersion: "rbac.authorization.k8s.io/v1",
				},
				ObjectMeta: metav1.ObjectMeta{
					Name:            "clusterrolebinding2",
					ResourceVersion: "320850103", // Same as the previous resource version
				},
				// Add roleRef, subjects, etc. for ClusterRoleBinding 2
			},
			{
				// ClusterRoleBinding 3
				TypeMeta: metav1.TypeMeta{
					Kind:       "ClusterRoleBinding",
					APIVersion: "rbac.authorization.k8s.io/v1",
				},
				ObjectMeta: metav1.ObjectMeta{
					Name:            "clusterrolebinding3",
					ResourceVersion: "320850103", // Same as the previous resource version
				},
				// Add roleRef, subjects, etc. for ClusterRoleBinding 3
			},
		},
	}

	// Convert the ClusterRoleBindingList object to JSON
	jsonResponse, err := json.Marshal(clusterRoleBindings)
	if err != nil {
		http.Error(w, "Error marshalling JSON response", http.StatusInternalServerError)
		return
	}

	// Set the response headers and write the JSON response
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	_, err = w.Write(jsonResponse)
	if err != nil {
		http.Error(w, fmt.Sprintf("Error writing the JSON response: %v", err), http.StatusInternalServerError)
		return
	}
}
0707010000002E000081A400000000000000000000000165DC12FD00000B94000000000000000000000000000000000000002B00000000kube-kompare-0.0.2~alpha3/mock/k8s_test.gopackage mock

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"
)

func TestStartMockCluster(t *testing.T) {
	clusterURL, mux, _ := StartMockCluster()

	// No need to defer a Close call for http.ServeMux

	// Assert that clusterURL is not empty
	if clusterURL == "" {
		t.Error("Expected clusterURL to be non-empty, got empty string")
	}

	// Test the /api/v1/namespaces endpoint
	req := httptest.NewRequest("GET", "/api/v1/namespaces", nil)
	w := httptest.NewRecorder()
	mux.ServeHTTP(w, req)
	resp := w.Result()

	if resp.StatusCode != http.StatusOK {
		t.Errorf("Expected status code %d, got %d", http.StatusOK, resp.StatusCode)
	}

	expectedContentType := "application/json"
	if contentType := resp.Header.Get("Content-Type"); contentType != expectedContentType {
		t.Errorf("Expected content type %s, got %s", expectedContentType, contentType)
	}
	// Test the /apis/apps/v1/namespaces/{namespace}/deployments endpoint
	deploymentsReq := httptest.NewRequest("GET", "/apis/apps/v1/namespaces/{namespace}/deployments", nil)
	deploymentsW := httptest.NewRecorder()
	mux.ServeHTTP(deploymentsW, deploymentsReq)
	deploymentsResp := deploymentsW.Result()

	if deploymentsResp.StatusCode != http.StatusOK {
		t.Errorf("Expected status code %d, got %d", http.StatusOK, deploymentsResp.StatusCode)
	}

	if contentType := deploymentsResp.Header.Get("Content-Type"); contentType != expectedContentType {
		t.Errorf("Expected content type %s, got %s", expectedContentType, contentType)
	}
}

func TestSetupTestEnvironment(t *testing.T) {
	sourceClusterURL, targetClusterURL, tempKubeconfig := SetupTestEnvironment()
	defer func() {
		err := tempKubeconfig.Close()
		if err != nil {
			t.Errorf("Error closing tempKubeconfig: %v", err)
		}
	}()

	// Check if the cluster URLs are not empty
	if sourceClusterURL == "" || targetClusterURL == "" {
		t.Error("Cluster URLs should not be empty")
	}

	// Check if tempKubeconfig is not nil
	if tempKubeconfig == nil {
		t.Error("Temp kubeconfig file should not be nil")
	}

	// Read the contents of tempKubeconfig and check if it's not empty
	// kubeconfigData := make([]byte, 1024)
	n, err := os.ReadFile(tempKubeconfig.Name())
	if err != nil {
		t.Errorf("Error reading kubeconfig file: %v", err)
	}

	// if n == 0 {
	// 	t.Error("Kubeconfig file should not be empty")
	// }

	// Ensure that the kubeconfig contains the expected cluster URLs
	expectedKubeconfigContent := fmt.Sprintf(`
apiVersion: v1
clusters:
- cluster:
    server: %s
  name: source-context
- cluster:
    server: %s
  name: target-context
contexts:
- context:
    cluster: source-context
    user: ""
  name: source-context
- context:
    cluster: target-context
    user: ""
  name: target-context
current-context: source-context
`, sourceClusterURL, targetClusterURL)

	if string(n) != expectedKubeconfigContent {
		t.Errorf("Expected kubeconfig content does not match\nExpected:\n%s\nGot:\n%s", expectedKubeconfigContent, string(n))
	}
}
0707010000002F000041ED00000000000000000000000265DC12FD00000000000000000000000000000000000000000000002000000000kube-kompare-0.0.2~alpha3/query07070100000030000081A400000000000000000000000165DC12FD0000232D000000000000000000000000000000000000002900000000kube-kompare-0.0.2~alpha3/query/query.gopackage query

import (
	"context"
	"fmt"
	"kompare/connect"

	v1 "k8s.io/api/apps/v1"
	autoscalingv1 "k8s.io/api/autoscaling/v1"
	batchv1 "k8s.io/api/batch/v1"

	networkingv1 "k8s.io/api/networking/v1"
	// traefikv1alpha1 "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1"
	apiextensionv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
	apiextension "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"

	Corev1 "k8s.io/api/core/v1"
	RbacV1 "k8s.io/api/rbac/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
)

// ListNameSpaces retrieves a list of Kubernetes namespaces.
// Parameters:
// - clientset: The Kubernetes clientset used to make the API call.
// Returns:
// - (*Corev1.NamespaceList): A list of Kubernetes namespaces.
// - (error): An error if any occurred during the API call.
func ListNameSpaces(clientset *kubernetes.Clientset) (*Corev1.NamespaceList, error) {
	nsList, err := clientset.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to query the NameSpace List: %w", err)
	}
	return nsList, nil
}

func GetNamespace(clientset *kubernetes.Clientset, name string) (*Corev1.Namespace, error) {
	ns, err := clientset.CoreV1().Namespaces().Get(context.TODO(), name, metav1.GetOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to query the NameSpace Get: %w", err)
	}
	return ns, nil
}

// ListK8sDeployments retrieves a list of Kubernetes deployments in the specified namespace.
// Parameters:
// - clientset: The Kubernetes clientset used to make the API call.
// - nameSpace: The namespace in which to list the deployments. If empty, uses the "default" namespace.
// Returns:
// - (*v1.DeploymentList): A list of Kubernetes deployments.
// - (error): An error if any occurred during the API call.
func ListDeployments(clientset *kubernetes.Clientset, nameSpace string) (*v1.DeploymentList, error) {
	if nameSpace == "" {
		nameSpace = "default"
	}
	deployments_list, err := clientset.AppsV1().Deployments(nameSpace).List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to query the Deployment List: %w", err)
	}
	return deployments_list, nil
}

// ListHPAs retrieves a list of HorizontalPodAutoscalers in the specified namespace.
// Parameters:
// - clientset: The Kubernetes clientset used to make the API call.
// - nameSpace: The namespace in which to list the HPAs. If empty, uses the "default" namespace.
// Returns:
// - (*autoscalingv1.HorizontalPodAutoscalerList): A list of HorizontalPodAutoscalers.
func ListHPAs(clientset *kubernetes.Clientset, nameSpace string) (*autoscalingv1.HorizontalPodAutoscalerList, error) {
	if nameSpace == "" {
		nameSpace = "default"
	}
	listHPA, err := clientset.AutoscalingV1().HorizontalPodAutoscalers(nameSpace).List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to query the HPA List: %w", err)
	}
	return listHPA, nil
}

// ListCronJobs retrieves a list of CronJobs in the specified namespace.
// Parameters:
// - clientset: The Kubernetes clientset used to make the API call.
// - nameSpace: The namespace in which to list the CronJobs.
// Returns:
// - (*batchv1.CronJobList): A list of CronJobs.
// - (error): An error if any occurred during the API call.
func ListCronJobs(clientset *kubernetes.Clientset, nameSpace string) (*batchv1.CronJobList, error) {
	listCronJobs, err := clientset.BatchV1().CronJobs(nameSpace).List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to query the Cron Job List: %w", err)
	}
	return listCronJobs, nil
}

// ListCRDs retrieves a list of CRDs in the specified namespace.
// Parameters:
// - kubeconfig: The Kubernetes client config used to make the API call.
// - nameSpace: The namespace in which to list the Ingresses.
// Returns:
// - (*apiextensionv1.CustomResourceDefinitionList): A list of CRDs.
// - (error): An error if any occurred during the API call.
func ListCRDs(ctx, kubeconfig string) (*apiextensionv1.CustomResourceDefinitionList, error) {
	config, err := connect.BuildConfigWithContextFromFlags(ctx, kubeconfig)
	if err != nil {
		return nil, fmt.Errorf("failed to create config for quering CRDs: %w", err)
	}
	kubeClient, err := apiextension.NewForConfig(config)
	if err != nil {
		return nil, fmt.Errorf("failed to get clientset for quering CRDs: %w", err)
	}

	listCRDs, err := kubeClient.ApiextensionsV1().CustomResourceDefinitions().List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to query the CRD List: %w", err)
	}
	return listCRDs, nil
}

// ListIngresses retrieves a list of Ingresses in the specified namespace.
// Parameters:
// - clientset: The Kubernetes clientset used to make the API call.
// - nameSpace: The namespace in which to list the Services.
// Returns:
// - (*networkingv1.IngressList): A list of Services.
// - (error): An error if any occurred during the API call.
func ListIngresses(clientset *kubernetes.Clientset, nameSpace string) (*networkingv1.IngressList, error) {
	listIngress, err := clientset.NetworkingV1().Ingresses(nameSpace).List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to query the Ingress List: %w", err)
	}
	return listIngress, nil
}

// ListServices retrieves a list of Services in the specified namespace.
// Parameters:
// - clientset: The Kubernetes clientset used to make the API call.
// - nameSpace: The namespace in which to list the Services.
// Returns:
// - (*Corev1.ServiceList): A list of Services.
// - (error): An error if any occurred during the API call.
func ListServices(clientset *kubernetes.Clientset, nameSpace string) (*Corev1.ServiceList, error) {
	listServices, err := clientset.CoreV1().Services(nameSpace).List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to query the Kubernetes Services List: %w", err)
	}
	return listServices, nil
}

// Get Config Maps list.
func ListConfigMaps(clientset *kubernetes.Clientset, nameSpace string) (*Corev1.ConfigMapList, error) {
	ListConfigMaps, err := clientset.CoreV1().ConfigMaps(nameSpace).List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to query the Config Map List: %w", err)
	}
	return ListConfigMaps, nil
}

// Get Secrets list.
func ListSecrets(clientset *kubernetes.Clientset, nameSpace string) (*Corev1.SecretList, error) {
	ListSercrets, err := clientset.CoreV1().Secrets(nameSpace).List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to query the Secrets List: %w", err)
	}
	return ListSercrets, nil
}

// Get Service Accounts list.
func ListServiceAccounts(clientset *kubernetes.Clientset, nameSpace string) (*Corev1.ServiceAccountList, error) {
	ListServiceAccounts, err := clientset.CoreV1().ServiceAccounts(nameSpace).List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to query the Service Accounts List: %w", err)
	}
	return ListServiceAccounts, nil
}

// roles
func ListRoles(clientset *kubernetes.Clientset, nameSpace string) (*RbacV1.RoleList, error) {
	Listroles, err := clientset.RbacV1().Roles(nameSpace).List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to query the Roles List: %w", err)
	}
	return Listroles, nil
}

// rolebindings
func ListRoleBindings(clientset *kubernetes.Clientset, nameSpace string) (*RbacV1.RoleBindingList, error) {
	ListRoleBindings, err := clientset.RbacV1().RoleBindings(nameSpace).List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to query the Role bindings List: %w", err)
	}
	return ListRoleBindings, nil
}

// clusterroles
func ListClusterRoles(clientset *kubernetes.Clientset) (*RbacV1.ClusterRoleList, error) {
	ListClusterRoles, err := clientset.RbacV1().ClusterRoles().List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to query the Cluster Roles List: %w", err)
	}
	return ListClusterRoles, nil
}

// clusterrolebindings
func ListClusterRoleBindings(clientset *kubernetes.Clientset) (*RbacV1.ClusterRoleBindingList, error) {
	ListClusterRoleBindings, err := clientset.RbacV1().ClusterRoleBindings().List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to query the Cluster Role Bindings List: %w", err)
	}
	return ListClusterRoleBindings, nil
}

// ListNetworkPolicy retrieves a list of NetworkPolicies in the specified namespace.
func ListNetworkPolicies(clientset *kubernetes.Clientset, nameSpace string) (*networkingv1.NetworkPolicyList, error) {
	listNetworkPolicy, err := clientset.NetworkingV1().NetworkPolicies(nameSpace).List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to query the Network Policy List: %w", err)
	}
	return listNetworkPolicy, nil
}
07070100000031000081A400000000000000000000000165DC12FD0000537E000000000000000000000000000000000000002E00000000kube-kompare-0.0.2~alpha3/query/query_test.gopackage query

import (
	"os"
	"testing"

	"kompare/connect"
	"kompare/mock"

	"k8s.io/client-go/tools/clientcmd"
)

func TestListNameSpaces(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes
	// Read the content of the kubeconfig file
	tempKubeconfigByte, err := os.ReadFile(tempKubeconfig.Name())
	if err != nil {
		t.Fatalf("Error reading kubeconfig file: %v", err)
	}
	// Load the kubeconfig data
	kubeconfig, err := clientcmd.Load(tempKubeconfigByte)
	if err != nil {
		t.Fatalf("Error loading kubeconfig: %v", err)
	}

	// Choose one of the contexts from the kubeconfig
	var testContext string
	for context := range kubeconfig.Contexts {
		testContext = context
		break // Choose the first context, you can modify this logic as needed
	}
	x := tempKubeconfig.Name()
	config, err := connect.ConnectToSource(testContext, &x)
	if err != nil {
		t.Fatalf("Error creating config: %v", err)
	}

	namespaces, err := ListNameSpaces(config)
	if err != nil {
		t.Errorf("Expected no error, got: %v", err)
	}

	expectedLength := 3
	if len(namespaces.Items) != expectedLength {
		t.Errorf("Expected %d namespaces, got: %d", expectedLength, len(namespaces.Items))
	}
}

func TestGetNamespace(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes
	// Read the content of the kubeconfig file
	tempKubeconfigByte, err := os.ReadFile(tempKubeconfig.Name())
	if err != nil {
		t.Fatalf("Error reading kubeconfig file: %v", err)
	}
	// Load the kubeconfig data
	kubeconfig, err := clientcmd.Load(tempKubeconfigByte)
	if err != nil {
		t.Fatalf("Error loading kubeconfig: %v", err)
	}

	// Choose one of the contexts from the kubeconfig
	var testContext string
	for context := range kubeconfig.Contexts {
		testContext = context
		break // Choose the first context, you can modify this logic as needed
	}
	x := tempKubeconfig.Name()
	config, err := connect.ConnectToSource(testContext, &x)
	if err != nil {
		t.Fatalf("Error creating config: %v", err)
	}

	namespace, err := GetNamespace(config, "namespace2")
	if err != nil {
		t.Errorf("Expected no error, got: %v", err)
	}

	if namespace.Name != "namespace2" {
		t.Errorf("Expected namespace2, got: %v", namespace)
	}
}

func TestListDeployments(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes

	// Read the content of the kubeconfig file
	tempKubeconfigByte, err := os.ReadFile(tempKubeconfig.Name())
	if err != nil {
		t.Fatalf("Error reading kubeconfig file: %v", err)
	}

	// Load the kubeconfig data
	kubeconfig, err := clientcmd.Load(tempKubeconfigByte)
	if err != nil {
		t.Fatalf("Error loading kubeconfig: %v", err)
	}

	// Choose one of the contexts from the kubeconfig
	var testContext string
	for context := range kubeconfig.Contexts {
		testContext = context
		break // Choose the first context, you can modify this logic as needed
	}

	x := tempKubeconfig.Name()
	config, err := connect.ConnectToSource(testContext, &x)
	if err != nil {
		t.Fatalf("Error creating config: %v", err)
	}

	// Perform the test
	deployments, err := ListDeployments(config, "namespace2")
	if err != nil {
		t.Errorf("Expected no error, got: %v", err)
	}

	expectedLength := 3 // Update this value with the expected number of deployments
	if len(deployments.Items) != expectedLength {
		t.Errorf("Expected %d deployments, got: %d", expectedLength, len(deployments.Items))
	}
}

func TestGetHPA(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes

	// Read the content of the kubeconfig file
	tempKubeconfigByte, err := os.ReadFile(tempKubeconfig.Name())
	if err != nil {
		t.Fatalf("Error reading kubeconfig file: %v", err)
	}

	// Load the kubeconfig data
	kubeconfig, err := clientcmd.Load(tempKubeconfigByte)
	if err != nil {
		t.Fatalf("Error loading kubeconfig: %v", err)
	}

	// Choose one of the contexts from the kubeconfig
	var testContext string
	for context := range kubeconfig.Contexts {
		testContext = context
		break // Choose the first context, you can modify this logic as needed
	}

	x := tempKubeconfig.Name()
	config, err := connect.ConnectToSource(testContext, &x)
	if err != nil {
		t.Fatalf("Error creating config: %v", err)
	}

	// Perform the test
	hpas, err := ListHPAs(config, "namespace2")
	if err != nil {
		t.Errorf("Expected no error, got: %v", err)
	}

	expectedLength := 3 // Update this value with the expected number of HPAs
	if len(hpas.Items) != expectedLength {
		t.Errorf("Expected %d HPAs, got: %d", expectedLength, len(hpas.Items))
	}
}

func TestListCronJobs(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes

	// Read the content of the kubeconfig file
	tempKubeconfigByte, err := os.ReadFile(tempKubeconfig.Name())
	if err != nil {
		t.Fatalf("Error reading kubeconfig file: %v", err)
	}

	// Load the kubeconfig data
	kubeconfig, err := clientcmd.Load(tempKubeconfigByte)
	if err != nil {
		t.Fatalf("Error loading kubeconfig: %v", err)
	}

	// Choose one of the contexts from the kubeconfig
	var testContext string
	for context := range kubeconfig.Contexts {
		testContext = context
		break // Choose the first context, you can modify this logic as needed
	}

	x := tempKubeconfig.Name()
	config, err := connect.ConnectToSource(testContext, &x)
	if err != nil {
		t.Fatalf("Error creating config: %v", err)
	}

	// Perform the test
	cronJobs, err := ListCronJobs(config, "namespace2")
	if err != nil {
		t.Errorf("Expected no error, got: %v", err)
	}

	expectedLength := 3 // Update this value with the expected number of CronJobs
	if len(cronJobs.Items) != expectedLength {
		t.Errorf("Expected %d CronJobs, got: %d", expectedLength, len(cronJobs.Items))
	}
}

func TestListCRDs(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes

	// Load the kubeconfig data
	tempKubeconfigByte, err := os.ReadFile(tempKubeconfig.Name())
	if err != nil {
		t.Fatalf("Error reading kubeconfig file: %v", err)
	}
	kubeconfig, err := clientcmd.Load(tempKubeconfigByte)
	if err != nil {
		t.Fatalf("Error loading kubeconfig: %v", err)
	}

	// Get the current context from the kubeconfig
	currentContext := kubeconfig.CurrentContext

	// Query the CRDs using the context and the kubeconfig file path
	crdList, err := ListCRDs(currentContext, tempKubeconfig.Name())
	if err != nil {
		t.Errorf("Expected no error, got: %v", err)
	}

	expectedLength := 3 // Adjust this based on your test case
	if len(crdList.Items) != expectedLength {
		t.Errorf("Expected %d CRDs, got: %d", expectedLength, len(crdList.Items))
	}
}

func TestListIngresses(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes

	// Read the content of the kubeconfig file
	tempKubeconfigByte, err := os.ReadFile(tempKubeconfig.Name())
	if err != nil {
		t.Fatalf("Error reading kubeconfig file: %v", err)
	}

	// Load the kubeconfig data
	kubeconfig, err := clientcmd.Load(tempKubeconfigByte)
	if err != nil {
		t.Fatalf("Error loading kubeconfig: %v", err)
	}

	// Choose one of the contexts from the kubeconfig
	var testContext string
	for context := range kubeconfig.Contexts {
		testContext = context
		break // Choose the first context, you can modify this logic as needed
	}

	// Connect to the Kubernetes cluster using the test context and kubeconfig file path
	x := tempKubeconfig.Name()
	config, err := connect.ConnectToSource(testContext, &x)
	if err != nil {
		t.Fatalf("Error creating config: %v", err)
	}

	// Perform the test
	ingresses, err := ListIngresses(config, "namespace2")
	if err != nil {
		t.Errorf("Expected no error, got: %v", err)
	}

	expectedLength := 3 // Update this value with the expected number of ingresses
	if len(ingresses.Items) != expectedLength {
		t.Errorf("Expected %d ingresses, got: %d", expectedLength, len(ingresses.Items))
	}
}

func TestListServices(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes

	// Read the content of the kubeconfig file
	tempKubeconfigByte, err := os.ReadFile(tempKubeconfig.Name())
	if err != nil {
		t.Fatalf("Error reading kubeconfig file: %v", err)
	}

	// Load the kubeconfig data
	kubeconfig, err := clientcmd.Load(tempKubeconfigByte)
	if err != nil {
		t.Fatalf("Error loading kubeconfig: %v", err)
	}

	// Choose one of the contexts from the kubeconfig
	var testContext string
	for context := range kubeconfig.Contexts {
		testContext = context
		break // Choose the first context, you can modify this logic as needed
	}
	// Connect to the Kubernetes cluster using the test context and kubeconfig file path
	x := tempKubeconfig.Name()
	config, err := connect.ConnectToSource(testContext, &x)
	if err != nil {
		t.Fatalf("Error creating config: %v", err)
	}
	// Perform the test
	services, err := ListServices(config, "namespace2")
	if err != nil {
		t.Errorf("Expected no error, got: %v", err)
	}

	expectedLength := 3 // Update this value with the expected number of services
	if len(services.Items) != expectedLength {
		t.Errorf("Expected %d services, got: %d", expectedLength, len(services.Items))
	}
}

// TestListConfigMaps tests the ListConfigMaps function.
func TestListConfigMaps(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes

	// Read the content of the kubeconfig file
	tempKubeconfigByte, err := os.ReadFile(tempKubeconfig.Name())
	if err != nil {
		t.Fatalf("Error reading kubeconfig file: %v", err)
	}

	// Load the kubeconfig data
	kubeconfig, err := clientcmd.Load(tempKubeconfigByte)
	if err != nil {
		t.Fatalf("Error loading kubeconfig: %v", err)
	}

	// Choose one of the contexts from the kubeconfig
	var testContext string
	for context := range kubeconfig.Contexts {
		testContext = context
		break // Choose the first context, you can modify this logic as needed
	}
	// Connect to the Kubernetes cluster using the test context and kubeconfig file path
	x := tempKubeconfig.Name()
	config, err := connect.ConnectToSource(testContext, &x)
	if err != nil {
		t.Fatalf("Error creating config: %v", err)
	}
	// Perform the test
	configMaps, err := ListConfigMaps(config, "namespace2")
	if err != nil {
		t.Errorf("Expected no error, got: %v", err)
	}

	expectedLength := 3 // Update this value with the expected number of config maps
	if len(configMaps.Items) != expectedLength {
		t.Errorf("Expected %d config maps, got: %d", expectedLength, len(configMaps.Items))
	}
}

// TestListSecrets tests the ListSecrets function.
func TestListSecrets(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes

	// Read the content of the kubeconfig file
	tempKubeconfigByte, err := os.ReadFile(tempKubeconfig.Name())
	if err != nil {
		t.Fatalf("Error reading kubeconfig file: %v", err)
	}

	// Load the kubeconfig data
	kubeconfig, err := clientcmd.Load(tempKubeconfigByte)
	if err != nil {
		t.Fatalf("Error loading kubeconfig: %v", err)
	}

	// Choose one of the contexts from the kubeconfig
	var testContext string
	for context := range kubeconfig.Contexts {
		testContext = context
		break // Choose the first context, you can modify this logic as needed
	}

	// Connect to the Kubernetes cluster using the test context and kubeconfig file path
	x := tempKubeconfig.Name()
	config, err := connect.ConnectToSource(testContext, &x)
	if err != nil {
		t.Fatalf("Error creating config: %v", err)
	}

	// Perform the test
	secrets, err := ListSecrets(config, "namespace2")
	if err != nil {
		t.Errorf("Expected no error, got: %v", err)
	}

	expectedLength := 3 // Update this value with the expected number of secrets
	if len(secrets.Items) != expectedLength {
		t.Errorf("Expected %d secrets, got: %d", expectedLength, len(secrets.Items))
	}
}

// TestListServiceAccounts tests the ListServiceAccounts function.
func TestListServiceAccounts(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes

	// Read the content of the kubeconfig file
	tempKubeconfigByte, err := os.ReadFile(tempKubeconfig.Name())
	if err != nil {
		t.Fatalf("Error reading kubeconfig file: %v", err)
	}

	// Load the kubeconfig data
	kubeconfig, err := clientcmd.Load(tempKubeconfigByte)
	if err != nil {
		t.Fatalf("Error loading kubeconfig: %v", err)
	}

	// Choose one of the contexts from the kubeconfig
	var testContext string
	for context := range kubeconfig.Contexts {
		testContext = context
		break // Choose the first context, you can modify this logic as needed
	}

	// Connect to the Kubernetes cluster using the test context and kubeconfig file path
	x := tempKubeconfig.Name()
	config, err := connect.ConnectToSource(testContext, &x)
	if err != nil {
		t.Fatalf("Error creating config: %v", err)
	}

	// Perform the test
	serviceAccounts, err := ListServiceAccounts(config, "namespace2")
	if err != nil {
		t.Errorf("Expected no error, got: %v", err)
	}

	expectedLength := 3 // Update this value with the expected number of service accounts
	if len(serviceAccounts.Items) != expectedLength {
		t.Errorf("Expected %d service accounts, got: %d", expectedLength, len(serviceAccounts.Items))
	}
}

// TestListRoles tests the ListRoles function.
func TestListRoles(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes

	// Read the content of the kubeconfig file
	tempKubeconfigByte, err := os.ReadFile(tempKubeconfig.Name())
	if err != nil {
		t.Fatalf("Error reading kubeconfig file: %v", err)
	}

	// Load the kubeconfig data
	kubeconfig, err := clientcmd.Load(tempKubeconfigByte)
	if err != nil {
		t.Fatalf("Error loading kubeconfig: %v", err)
	}

	// Choose one of the contexts from the kubeconfig
	var testContext string
	for context := range kubeconfig.Contexts {
		testContext = context
		break // Choose the first context, you can modify this logic as needed
	}

	// Connect to the Kubernetes cluster using the test context and kubeconfig file path
	x := tempKubeconfig.Name()
	config, err := connect.ConnectToSource(testContext, &x)
	if err != nil {
		t.Fatalf("Error creating config: %v", err)
	}

	// Perform the test
	roles, err := ListRoles(config, "namespace2")
	if err != nil {
		t.Errorf("Expected no error, got: %v", err)
	}

	expectedLength := 3 // Update this value with the expected number of roles
	if len(roles.Items) != expectedLength {
		t.Errorf("Expected %d roles, got: %d", expectedLength, len(roles.Items))
	}
}

// TestListRoleBindings tests the ListRoleBindings function.
func TestListRoleBindings(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes

	// Read the content of the kubeconfig file
	tempKubeconfigByte, err := os.ReadFile(tempKubeconfig.Name())
	if err != nil {
		t.Fatalf("Error reading kubeconfig file: %v", err)
	}

	// Load the kubeconfig data
	kubeconfig, err := clientcmd.Load(tempKubeconfigByte)
	if err != nil {
		t.Fatalf("Error loading kubeconfig: %v", err)
	}

	// Choose one of the contexts from the kubeconfig
	var testContext string
	for context := range kubeconfig.Contexts {
		testContext = context
		break // Choose the first context, you can modify this logic as needed
	}

	// Connect to the Kubernetes cluster using the test context and kubeconfig file path
	x := tempKubeconfig.Name()
	config, err := connect.ConnectToSource(testContext, &x)
	if err != nil {
		t.Fatalf("Error creating config: %v", err)
	}

	// Perform the test
	roleBindings, err := ListRoleBindings(config, "namespace2")
	if err != nil {
		t.Errorf("Expected no error, got: %v", err)
	}

	expectedLength := 3 // Update this value with the expected number of role bindings
	if len(roleBindings.Items) != expectedLength {
		t.Errorf("Expected %d role bindings, got: %d", expectedLength, len(roleBindings.Items))
	}
}

// TestListClusterRoles tests the ListClusterRoles function.
func TestListClusterRoles(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes

	// Load the kubeconfig data
	tempKubeconfigByte, err := os.ReadFile(tempKubeconfig.Name())
	if err != nil {
		t.Fatalf("Error reading kubeconfig file: %v", err)
	}
	kubeconfig, err := clientcmd.Load(tempKubeconfigByte)
	if err != nil {
		t.Fatalf("Error loading kubeconfig: %v", err)
	}

	// Choose one of the contexts from the kubeconfig
	var testContext string
	for context := range kubeconfig.Contexts {
		testContext = context
		break // Choose the first context, you can modify this logic as needed
	}
	x := tempKubeconfig.Name()
	config, err := connect.ConnectToSource(testContext, &x)
	if err != nil {
		t.Fatalf("Error creating config: %v", err)
	}
	// Perform the test
	clusterRoles, err := ListClusterRoles(config)
	if err != nil {
		t.Errorf("Expected no error, got: %v", err)
	}

	expectedLength := 3 // Update this value with the expected number of cluster roles
	if len(clusterRoles.Items) != expectedLength {
		t.Errorf("Expected %d cluster roles, got: %d", expectedLength, len(clusterRoles.Items))
	}
}

// TestListRoleBindings tests the ListRoleBindings function.
func TestListRoleBindings2(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes

	// Load the kubeconfig data
	tempKubeconfigByte, err := os.ReadFile(tempKubeconfig.Name())
	if err != nil {
		t.Fatalf("Error reading kubeconfig file: %v", err)
	}
	kubeconfig, err := clientcmd.Load(tempKubeconfigByte)
	if err != nil {
		t.Fatalf("Error loading kubeconfig: %v", err)
	}

	// Choose one of the contexts from the kubeconfig
	var testContext string
	for context := range kubeconfig.Contexts {
		testContext = context
		break // Choose the first context, you can modify this logic as needed
	}
	x := tempKubeconfig.Name()
	config, err := connect.ConnectToSource(testContext, &x)
	if err != nil {
		t.Fatalf("Error creating config: %v", err)
	}

	// Perform the test
	roleBindings, err := ListRoleBindings(config, "namespace2")
	if err != nil {
		t.Errorf("Expected no error, got: %v", err)
	}

	expectedLength := 3 // Update this value with the expected number of role bindings
	if len(roleBindings.Items) != expectedLength {
		t.Errorf("Expected %d role bindings, got: %d", expectedLength, len(roleBindings.Items))
	}

}

// TestNetworkPolicies tests the ListNetworkPolicies function.
func TestListNetworkPolicies(t *testing.T) {
	// Set up test environment and get the temporary kubeconfig file
	_, _, tempKubeconfig := mock.SetupTestEnvironment()
	defer tempKubeconfig.Close() // Close the file after the test completes

	// Load the kubeconfig data
	tempKubeconfigByte, err := os.ReadFile(tempKubeconfig.Name())
	if err != nil {
		t.Fatalf("Error reading kubeconfig file: %v", err)
	}
	kubeconfig, err := clientcmd.Load(tempKubeconfigByte)
	if err != nil {
		t.Fatalf("Error loading kubeconfig: %v", err)
	}

	// Choose one of the contexts from the kubeconfig
	var testContext string
	for context := range kubeconfig.Contexts {
		testContext = context
		break // Choose the first context, you can modify this logic as needed
	}

	// Connect to the Kubernetes cluster using the test context and kubeconfig file path
	x := tempKubeconfig.Name()
	config, err := connect.ConnectToSource(testContext, &x)
	if err != nil {
		t.Fatalf("Error creating config: %v", err)
	}

	// Perform the test
	networkPolicies, err := ListNetworkPolicies(config, "namespace2")
	if err != nil {
		t.Errorf("Expected no error, got: %v", err)
	}

	expectedLength := 3 // Update this value with the expected number of network policies
	if len(networkPolicies.Items) != expectedLength {
		t.Errorf("Expected %d network policies, got: %d", expectedLength, len(networkPolicies.Items))
	}
}
07070100000032000041ED00000000000000000000000265DC12FD00000000000000000000000000000000000000000000002000000000kube-kompare-0.0.2~alpha3/tools07070100000033000081A400000000000000000000000165DC12FD00001201000000000000000000000000000000000000003100000000kube-kompare-0.0.2~alpha3/tools/diffs-handler.gopackage tools

import (
	"encoding/json"
	"fmt"
	"strings"

	"kompare/DAO"
)

// FormatDiffHumanReadable formats differences in a human-readable format.
// It takes a slice of DiffWithName (differences) containing information about differences between resources.
// It iterates over each difference and constructs a human-readable format containing details such as resource type, object name, namespace, and specific differences.
// If a property name, object name, namespace, or differences exist for a particular difference, it includes them in the formatted output.
// The function returns a string containing the human-readable formatted differences.
func FormatDiffHumanReadable(differences []DAO.DiffWithName) string {
	var formattedDiff strings.Builder
	for _, diff := range differences {
		if len(diff.Diff) != 0 {
			if diff.PropertyName != "" {
				formattedDiff.WriteString(fmt.Sprintf("Kubernetes resource definition type: %s\n", diff.PropertyName))
			}
			if diff.Name != "" {
				formattedDiff.WriteString(fmt.Sprintf("Object Name: %s\n", diff.Name))
			}
			if diff.Namespace != "" {
				formattedDiff.WriteString(fmt.Sprintf("Namespace: %s\n", diff.Namespace))
			}
			formattedDiff.WriteString("Differences:\n")
			if len(diff.Diff) > 0 {
				for _, d := range diff.Diff {
					key, value, result := startsWithMapPattern(d)
					if result {
						x, y, z := ExtractSubstrings(value)
						leftMultiline := strings.Contains(x, "\n")
						rightMultiline := strings.Contains(z, "\n")
						if leftMultiline || rightMultiline {
							formattedDiff.WriteString(fmt.Sprintf("- %s:\n", key))
							if isJSONCompatible(x) {
								prettyX, err := prettifyJSON(x)
								if err != nil {
									// Handle error
									formattedDiff.WriteString(fmt.Sprintf("Error prettifying left side JSON: %v\n", err))
								} else {
									formattedDiff.WriteString(fmt.Sprintf("%s\n", prettyX))
								}
							} else {
								formattedDiff.WriteString(fmt.Sprintf("%s:\n", x))
							}
							formattedDiff.WriteString(fmt.Sprintf(" %s\n", y))
							if isJSONCompatible(z) {
								prettyZ, err := prettifyJSON(z)
								if err != nil {
									// Handle error
									formattedDiff.WriteString(fmt.Sprintf("Error prettifying right side JSON: %v\n", err))
								} else {
									formattedDiff.WriteString(fmt.Sprintf("%s\n", prettyZ))
								}
							} else {
								formattedDiff.WriteString(fmt.Sprintf("%s:\n", z))
							}
						} else {
							formattedDiff.WriteString(fmt.Sprintf("- %s: %s %s %s\n", key, x, y, z))
						}
					} else {
						formattedDiff.WriteString(fmt.Sprintf("- %v\n", d))
					}
				}
				formattedDiff.WriteString("\n")
			}
		} else {
			if diff.Namespace != "" {
				fmt.Printf("No differences found; Object Name %s, Kubernetes resource definition type %s, Namespace %s\n", diff.Name, diff.PropertyName, diff.Namespace)
			} else {
				fmt.Printf("No differences found; Object Name %s, Kubernetes resource definition type %s\n", diff.Name, diff.PropertyName)
			}
		}
	}
	return formattedDiff.String()
}

func startsWithMapPattern(input string) (string, string, bool) {
	// Define the prefix pattern
	prefix := "map["
	// Check if the input string starts with the prefix
	if strings.Contains(input, prefix) {
		// Find the index of the closing bracket "]"
		closingBracketIndex := strings.Index(input, ":")

		// Check if the closing bracket is followed by a colon ":"
		if closingBracketIndex != -1 && closingBracketIndex < len(input)-1 && input[closingBracketIndex+1] == ':' {
			// Extract the substring between the brackets and after the colon
			key := strings.TrimSpace(input[len(prefix):closingBracketIndex])
			value := strings.TrimSpace(input[closingBracketIndex+1:]) // Trimming spaces
			return key, value, true
		}
	}

	return "", "", false
}

func ExtractSubstrings(value string) (string, string, string) {
	parts := strings.Split(value, "!= ")

	if len(parts) < 2 {
		return "", "", ""
	}

	leftSide := parts[0]
	rightSide := parts[1]

	// Split operatorAndRightSide to get the operator and right side
	leftSide = strings.TrimSpace(leftSide)
	rightSide = strings.TrimSpace(rightSide)
	return leftSide, "!=", rightSide
}

func isJSONCompatible(jsonStr string) bool {
	var data interface{}
	err := json.Unmarshal([]byte(jsonStr), &data)
	return err == nil
}

func prettifyJSON(jsonStr string) (string, error) {
	var data interface{}
	err := json.Unmarshal([]byte(jsonStr), &data)
	if err != nil {
		return "", err
	}
	prettyJSON, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		return "", err
	}
	return string(prettyJSON), nil
}
07070100000034000081A400000000000000000000000165DC12FD00000681000000000000000000000000000000000000003600000000kube-kompare-0.0.2~alpha3/tools/diffs-handler_test.gopackage tools

import (
	"testing"
)

func TestIsJSONCompatible(t *testing.T) {
	tests := []struct {
		name     string
		jsonStr  string
		expected bool
	}{
		{
			name:     "Valid JSON string",
			jsonStr:  `{"key": "value"}`,
			expected: true,
		},
		{
			name:     "Invalid JSON string",
			jsonStr:  `{"key": "value"`,
			expected: false,
		},
		{
			name:     "Empty string",
			jsonStr:  "",
			expected: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := isJSONCompatible(tt.jsonStr)
			if result != tt.expected {
				t.Errorf("Expected isJSONCompatible(%s) to be %t, got %t", tt.jsonStr, tt.expected, result)
			}
		})
	}
}

func TestPrettifyJSON(t *testing.T) {
	tests := []struct {
		name          string
		jsonStr       string
		expectedJSON  string
		expectedError bool
	}{
		{
			name:          "Valid JSON string",
			jsonStr:       `{"key": "value"}`,
			expectedJSON:  "{\n  \"key\": \"value\"\n}",
			expectedError: false,
		},
		{
			name:          "Invalid JSON string",
			jsonStr:       `{"key": "value"`,
			expectedJSON:  "",
			expectedError: true,
		},
		{
			name:          "Empty string",
			jsonStr:       "",
			expectedJSON:  "",
			expectedError: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result, err := prettifyJSON(tt.jsonStr)
			if (err != nil) != tt.expectedError {
				t.Errorf("Expected error status does not match for prettifyJSON(%s)", tt.jsonStr)
			}
			if tt.expectedError {
				return
			}
			if result != tt.expectedJSON {
				t.Errorf("Expected prettifyJSON(%s) to be %s, got %s", tt.jsonStr, tt.expectedJSON, result)
			}
		})
	}
}
07070100000035000081A400000000000000000000000165DC12FD00000C2B000000000000000000000000000000000000002E00000000kube-kompare-0.0.2~alpha3/tools/file-works.gopackage tools

import (
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

// isValidPath checks if the given path is valid for the current operating system.
func IsValidPath(path string) (isValid bool, absPath string, err error) {
	// Check if the path contains invalid characters for the current OS.
	var invalidChars string
	switch runtime.GOOS {
	case "windows":
		invalidChars = `<>|?*`
	default:
		invalidChars = `<>:"\|?*`
	}

	for _, char := range invalidChars {
		if strings.ContainsRune(path, char) {
			return false, "", fmt.Errorf("invalid character '%c' found in the path", char)
		}
	}

	// Check if the path is empty or consists of only whitespace characters.
	if len(strings.TrimSpace(path)) == 0 {
		return false, "", fmt.Errorf("empty path")
	}

	// Convert the path to absolute path if it's relative.
	if !filepath.IsAbs(path) {
		// Get the current working directory.
		cwd, err := os.Getwd()
		if err != nil {
			// Failed to get the current working directory.
			return false, "", err
		}
		// Join the current working directory with the relative path to get absolute path.
		absPath = filepath.Join(cwd, path)
	} else {
		absPath = path
	}

	// Try to create or open the file.
	file, err := os.OpenFile(absPath, os.O_RDWR|os.O_CREATE, 0666)
	if err != nil {
		// Check if the error is due to a missing directory in the path.
		if os.IsNotExist(err) {
			return false, "", fmt.Errorf("the file or one or more directories in the path do not exist or can not be created: %v", err)
		}
		// Check if the error is due to permission issues.
		if os.IsPermission(err) {
			return false, "", fmt.Errorf("no permission to write on path: %s", absPath)
		}
		// For other errors, return the error as is.
		return false, "", err
	}
	// Defer the closure of the file and its removal.
	defer func() {
		file.Close()
		os.Remove(absPath)
	}()

	return true, absPath, nil
}

func LogOutput(logfile string) func() {
	// open file read/write | create if not exist | clear file at open if exists
	f, _ := os.OpenFile(logfile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)

	// save existing stdout | MultiWriter writes to saved stdout and file
	out := os.Stdout
	mw := io.MultiWriter(out, f)

	// get pipe reader and writer | writes to pipe writer come out pipe reader
	r, w, _ := os.Pipe()

	// replace stdout,stderr with pipe writer | all writes to stdout, stderr will go through pipe instead (fmt.print, log)
	os.Stdout = w
	os.Stderr = w

	// writes with log.Print should also write to mw
	log.SetOutput(mw)

	//create channel to control exit | will block until all copies are finished
	exit := make(chan bool)

	go func() {
		// copy all reads from pipe to multiwriter, which writes to stdout and file
		_, _ = io.Copy(mw, r)
		// when r or w is closed copy will finish and true will be sent to channel
		exit <- true
	}()

	// function to be deferred in main until program exits
	return func() {
		// close writer then block on exit channel | this will let mw finish writing before the program exits
		_ = w.Close()
		<-exit
		// close file after all writes have finished
		_ = f.Close()
	}

}
07070100000036000081A400000000000000000000000165DC12FD00000CB0000000000000000000000000000000000000003300000000kube-kompare-0.0.2~alpha3/tools/file-works_test.gopackage tools

import (
	"log"
	"os"
	"strings"
	"testing"
)

func TestIsValidPath(t *testing.T) {
	// Example usage:
	paths := map[string]struct {
		expectedValid bool
		expectedError string
	}{
		"/path/to/valid/file.txt": {
			expectedValid: false,
			expectedError: "the file or one or more directories in the path do not exist or can not be created",
		},
		"invalid*file.txt": {
			expectedValid: false,
			expectedError: "invalid character '*' found in the path",
		},
		"": {
			expectedValid: false,
			expectedError: "empty path",
		},
		"  ": {
			expectedValid: false,
			expectedError: "empty path",
		},
		"/path/with/invalid|character": {
			expectedValid: false,
			expectedError: "invalid character '|' found in the path",
		},
		"C:\\Program Files\\Example\\file.txt": {
			expectedValid: false,
			expectedError: "invalid character ':' found in the path",
		},
		"D:/Documents/Report.docx": {
			expectedValid: false,
			expectedError: "invalid character ':' found in the path",
		},
		"/home/user/pictures/photo.jpg": {
			expectedValid: false,
			expectedError: "the file or one or more directories in the path do not exist or can not be created",
		},
		"file.txt": {
			expectedValid: true,
			expectedError: "",
		},
		"folder1/file.txt": {
			expectedValid: false,
			expectedError: "the file or one or more directories in the path do not exist or can not be created",
		},
		"../parent/file.txt": {
			expectedValid: false,
			expectedError: "the file or one or more directories in the path do not exist or can not be created",
		},
		"..\\parent\\file.txt": {
			expectedValid: false,
			expectedError: "invalid character '\\' found in the path",
		},
	}

	for path, expected := range paths {
		valid, _, err := IsValidPath(path)
		if err != nil {
			if !strings.Contains(err.Error(), expected.expectedError) {
				t.Errorf("Unexpected error for path %s. Expected: %s, Got: %s", path, expected.expectedError, err.Error())
			}
		} else {
			if valid != expected.expectedValid {
				t.Errorf("Path %s validation failed. Expected valid: %t but got: %t", path, expected.expectedValid, valid)
			}
		}
	}
}

func TestLogOutput(t *testing.T) {
	// Create a temporary file for logging
	tmpfile, err := os.CreateTemp("", "testlog-")
	if err != nil {
		t.Fatalf("Error creating temporary file: %v", err)
	}
	defer os.Remove(tmpfile.Name())

	// Create a channel to signal when the goroutine has completed
	done := make(chan struct{})

	// Call LogOutput with the temporary file
	go func() {
		defer close(done)
		LogOutput(tmpfile.Name()) // Assuming LogOutput returns immediately after starting the goroutine
	}()

	// Write a log message
	log.Print("Test log message")

	// Wait for the goroutine to finish
	<-done

	// Read and verify the contents of the log file
	// (You should implement this verification logic)
}

func TestLogOutputWithInvalidPath(t *testing.T) {
	// Call LogOutput with an invalid path
	err := LogOutput("invalid*file.txt")
	if err == nil {
		t.Errorf("Expected error for invalid path")
	}
	defer os.Remove("invalid*file.txt")
}

func TestLogOutputWithEmptyPath(t *testing.T) {
	// Call LogOutput with an empty path
	err := LogOutput("")
	if err == nil {
		t.Errorf("Expected error for empty path")
	}
}
07070100000037000081A400000000000000000000000165DC12FD00000635000000000000000000000000000000000000003300000000kube-kompare-0.0.2~alpha3/tools/strings-handler.gopackage tools

import (
	"reflect"
	"strings"
	"unicode"
)

func ConvertTypeStringToHumanReadable(what interface{}) string {
	objType := reflect.TypeOf(what)

	// If it's a pointer, get the element type
	if objType.Kind() == reflect.Ptr {
		objType = objType.Elem()
	}

	// Get the package and type names
	aString := objType.Name()
	// pkgPath := objType.PkgPath()
	dotIndex := strings.Index(aString, ".")
	aString = aString[dotIndex+1:]
	aString = convertCamelCaseToSpaces(aString)
	// Transform "List" to "in the list"
	aString = strings.TrimSuffix(aString, " List")
	aString += " in the list"
	return aString
}

func convertCamelCaseToSpaces(s string) string {
	var result string
	for i, char := range s {
		if i > 0 && unicode.IsUpper(char) {
			result += " "
		}
		result += string(char)
	}
	return result
}

func ParseCommaSeparateList(s string) []string {
	if s == "" {
		return []string{}
	}

	return strings.Split(s, ",")
}

// IsInList checks if a string is present in a list of strings
func IsInList(str string, list []string) bool {
	for _, s := range list {
		if str == s {
			return true
		}
	}
	return false
}

// AreAnyInLists checks if any element from the first list is present in the second list
func AreAnyInLists(list1, list2 []string) bool {
	for _, s1 := range list1 {
		for _, s2 := range list2 {
			if s1 == s2 {
				return true
			}
		}
	}
	return false
}

// HasCharacter checks if a string contains a specific character
func HasCharacter(str string, char byte) bool {
	for i := 0; i < len(str); i++ {
		if str[i] == char {
			return true
		}
	}
	return false
}
07070100000038000081A400000000000000000000000165DC12FD00000675000000000000000000000000000000000000003800000000kube-kompare-0.0.2~alpha3/tools/strings-handler_test.gopackage tools

import (
	"reflect"
	"testing"
)

func TestConvertCamelCaseToSpaces(t *testing.T) {
	type TestCase struct {
		input    string
		expected string
	}

	tests := []TestCase{
		{input: "camelCaseString", expected: "camel Case String"},
		{input: "HTTPResponse", expected: "H T T P Response"},
		{input: "anotherString", expected: "another String"},
	}

	for _, tc := range tests {
		actual := convertCamelCaseToSpaces(tc.input)
		if actual != tc.expected {
			t.Errorf("Expected %s, but got %s", tc.expected, actual)
		}
	}
}

func TestParseCommaSeparateList(t *testing.T) {
	input := "apple,banana,orange"
	expected := []string{"apple", "banana", "orange"}

	actual := ParseCommaSeparateList(input)
	if !reflect.DeepEqual(actual, expected) {
		t.Errorf("Expected %v, but got %v", expected, actual)
	}
}

func TestIsInList(t *testing.T) {
	list := []string{"apple", "banana", "orange"}

	if !IsInList("apple", list) {
		t.Errorf("Expected 'apple' to be in the list")
	}

	if IsInList("grape", list) {
		t.Errorf("Expected 'grape' not to be in the list")
	}
}

func TestAreAnyInLists(t *testing.T) {
	list1 := []string{"apple", "banana", "orange"}
	list2 := []string{"orange", "grape"}

	if !AreAnyInLists(list1, list2) {
		t.Errorf("Expected elements from list1 to be in list2")
	}

	list3 := []string{"pear", "peach"}

	if AreAnyInLists(list1, list3) {
		t.Errorf("Expected elements from list1 not to be in list3")
	}
}

func TestHasCharacter(t *testing.T) {
	str := "hello"

	if !HasCharacter(str, 'h') {
		t.Errorf("Expected 'h' to be in the string")
	}

	if HasCharacter(str, 'z') {
		t.Errorf("Expected 'z' not to be in the string")
	}
}
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!425 blocks
openSUSE Build Service is sponsored by